1 /*****************************************************************************\
3 *****************************************************************************
4 * Please also read the file DISCLAIMER which is included in this software
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License (as published by the
9 * Free Software Foundation) version 2, dated June 1991.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
14 * conditions of the GNU General Public License for more details.
15 \*****************************************************************************/
22 #include "coreboot_tables.h"
23 #include "ip_checksum.h"
26 #include "cmos_lowlevel.h"
29 #include "layout-text.h"
31 static void process_cmos_table(void);
32 static void get_cmos_checksum_info(void);
33 static void try_convert_checksum_layout(cmos_checksum_layout_t
* layout
);
34 static void try_add_cmos_table_enum(cmos_enum_t
* cmos_enum
);
35 static void try_add_cmos_table_entry(cmos_entry_t
* cmos_entry
);
36 static const struct cmos_entries
*first_cmos_table_entry(void);
37 static const struct cmos_entries
*next_cmos_table_entry(const struct
39 static const struct cmos_enums
*first_cmos_table_enum(void);
40 static const struct cmos_enums
*next_cmos_table_enum
41 (const struct cmos_enums
*last
);
42 static const struct lb_record
*first_cmos_rec(uint32_t tag
);
43 static const struct lb_record
*next_cmos_rec(const struct lb_record
*last
,
46 /* The CMOS option table is located within the coreboot table. It tells us
47 * where the CMOS parameters are located in the nonvolatile RAM.
49 static const struct cmos_option_table
*cmos_table
= NULL
;
51 #define ROUNDUP4(x) (x += (4 - (x % 4)))
53 void process_layout(void)
55 if ((cmos_table
) == NULL
) {
57 "%s: CMOS option table not found in coreboot table. "
58 "Apparently, the coreboot installed on this system was "
59 "built without selecting CONFIG_USE_OPTION_TABLE.\n",
65 get_cmos_checksum_info();
68 void get_layout_from_cbfs_file(void)
71 cmos_table
= cbfs_find_file("cmos_layout.bin", CBFS_COMPONENT_CMOS_LAYOUT
, &len
);
75 static int write_cmos_layout_bin(FILE *f
)
77 const cmos_entry_t
*cmos_entry
;
78 const cmos_enum_t
*cmos_enum
;
79 cmos_checksum_layout_t layout
;
80 struct cmos_option_table table
;
81 struct cmos_entries entry
;
82 struct cmos_enums cenum
;
83 struct cmos_checksum csum
;
87 for (cmos_entry
= first_cmos_entry(); cmos_entry
!= NULL
;
88 cmos_entry
= next_cmos_entry(cmos_entry
)) {
90 if (cmos_entry
== first_cmos_entry()) {
92 table
.header_length
= sizeof(table
);
93 table
.tag
= LB_TAG_CMOS_OPTION_TABLE
;
96 if (fwrite((char *)&table
, sizeof(table
), 1, f
) != 1) {
97 perror("Error writing image file");
102 memset(&entry
, 0, sizeof(entry
));
103 entry
.tag
= LB_TAG_OPTION
;
104 entry
.config
= cmos_entry
->config
;
105 entry
.config_id
= (uint32_t)cmos_entry
->config_id
;
106 entry
.bit
= cmos_entry
->bit
;
107 entry
.length
= cmos_entry
->length
;
109 if (!is_ident((char *)cmos_entry
->name
)) {
111 "Error - Name %s is an invalid identifier\n",
116 memcpy(entry
.name
, cmos_entry
->name
, strlen(cmos_entry
->name
));
117 entry
.name
[strlen(cmos_entry
->name
)] = '\0';
118 len
= strlen(cmos_entry
->name
) + 1;
123 entry
.size
= sizeof(entry
) - CMOS_MAX_NAME_LENGTH
+ len
;
125 if (fwrite((char *)&entry
, entry
.size
, 1, f
) != 1) {
126 perror("Error writing image file");
131 for (cmos_enum
= first_cmos_enum();
132 cmos_enum
!= NULL
; cmos_enum
= next_cmos_enum(cmos_enum
)) {
133 memset(&cenum
, 0, sizeof(cenum
));
134 cenum
.tag
= LB_TAG_OPTION_ENUM
;
135 memcpy(cenum
.text
, cmos_enum
->text
, strlen(cmos_enum
->text
));
136 cenum
.text
[strlen(cmos_enum
->text
)] = '\0';
137 len
= strlen((char *)cenum
.text
) + 1;
142 cenum
.config_id
= cmos_enum
->config_id
;
143 cenum
.value
= cmos_enum
->value
;
144 cenum
.size
= sizeof(cenum
) - CMOS_MAX_TEXT_LENGTH
+ len
;
146 if (fwrite((char *)&cenum
, cenum
.size
, 1, f
) != 1) {
147 perror("Error writing image file");
152 layout
.summed_area_start
= cmos_checksum_start
;
153 layout
.summed_area_end
= cmos_checksum_end
;
154 layout
.checksum_at
= cmos_checksum_index
;
155 checksum_layout_to_bits(&layout
);
157 csum
.tag
= LB_TAG_OPTION_CHECKSUM
;
158 csum
.size
= sizeof(csum
);
159 csum
.range_start
= layout
.summed_area_start
;
160 csum
.range_end
= layout
.summed_area_end
;
161 csum
.location
= layout
.checksum_at
;
162 csum
.type
= CHECKSUM_PCBIOS
;
165 if (fwrite((char *)&csum
, csum
.size
, 1, f
) != 1) {
166 perror("Error writing image file");
170 if (fseek(f
, 0, SEEK_SET
) != 0) {
171 perror("Error while seeking");
176 if (fwrite((char *)&table
, sizeof(table
), 1, f
) != 1) {
177 perror("Error writing image file");
187 void write_cmos_output_bin(const char *binary_filename
)
191 if ((fp
= fopen(binary_filename
, "wb")) == NULL
) {
193 "%s: Can not open file %s for writing: "
194 "%s\n", prog_name
, binary_filename
, strerror(errno
));
197 write_cmos_layout_bin(fp
);
201 /****************************************************************************
202 * get_layout_from_cmos_table
204 * Find the CMOS table which is stored within the coreboot table and set the
205 * global variable cmos_table to point to it.
206 ****************************************************************************/
207 void get_layout_from_cmos_table(void)
210 cmos_table
= (const struct cmos_option_table
*)
211 find_lbrec(LB_TAG_CMOS_OPTION_TABLE
);
215 /****************************************************************************
218 * Extract layout information from the CMOS option table and store it in our
219 * internal repository.
220 ****************************************************************************/
221 static void process_cmos_table(void)
223 const struct cmos_enums
*p
;
224 const struct cmos_entries
*q
;
225 cmos_enum_t cmos_enum
;
226 cmos_entry_t cmos_entry
;
228 /* First add the enums. */
229 for (p
= first_cmos_table_enum(); p
!= NULL
;
230 p
= next_cmos_table_enum(p
)) {
231 cmos_enum
.config_id
= p
->config_id
;
232 cmos_enum
.value
= p
->value
;
233 strncpy(cmos_enum
.text
, (char *)p
->text
, CMOS_MAX_TEXT_LENGTH
);
234 cmos_enum
.text
[CMOS_MAX_TEXT_LENGTH
] = '\0';
235 try_add_cmos_table_enum(&cmos_enum
);
238 /* Now add the entries. We must add the entries after the enums because
239 * the entries are sanity checked against the enums as they are added.
241 for (q
= first_cmos_table_entry(); q
!= NULL
;
242 q
= next_cmos_table_entry(q
)) {
243 cmos_entry
.bit
= q
->bit
;
244 cmos_entry
.length
= q
->length
;
248 cmos_entry
.config
= CMOS_ENTRY_ENUM
;
252 cmos_entry
.config
= CMOS_ENTRY_HEX
;
256 cmos_entry
.config
= CMOS_ENTRY_RESERVED
;
260 cmos_entry
.config
= CMOS_ENTRY_STRING
;
265 "%s: Entry in CMOS option table has unknown config "
266 "value.\n", prog_name
);
270 cmos_entry
.config_id
= q
->config_id
;
271 strncpy(cmos_entry
.name
, (char *)q
->name
, CMOS_MAX_NAME_LENGTH
);
272 cmos_entry
.name
[CMOS_MAX_NAME_LENGTH
] = '\0';
273 try_add_cmos_table_entry(&cmos_entry
);
277 /****************************************************************************
278 * get_cmos_checksum_info
280 * Get layout information for CMOS checksum.
281 ****************************************************************************/
282 static void get_cmos_checksum_info(void)
284 const cmos_entry_t
*e
;
285 struct cmos_checksum
*checksum
;
286 cmos_checksum_layout_t layout
;
287 unsigned index
, index2
;
289 checksum
= (struct cmos_checksum
*)next_cmos_rec((const struct lb_record
*)first_cmos_table_enum(), LB_TAG_OPTION_CHECKSUM
);
291 if (checksum
!= NULL
) { /* We are lucky. The coreboot table hints us to the checksum.
292 * We might have to check the type field here though.
294 layout
.summed_area_start
= checksum
->range_start
;
295 layout
.summed_area_end
= checksum
->range_end
;
296 layout
.checksum_at
= checksum
->location
;
297 try_convert_checksum_layout(&layout
);
298 cmos_checksum_start
= layout
.summed_area_start
;
299 cmos_checksum_end
= layout
.summed_area_end
;
300 cmos_checksum_index
= layout
.checksum_at
;
304 if ((e
= find_cmos_entry(checksum_param_name
)) == NULL
)
307 /* If we get here, we are unlucky. The CMOS option table contains the
308 * location of the CMOS checksum. However, there is no information
309 * regarding which bytes of the CMOS area the checksum is computed over.
310 * Thus we have to hope our presets will be fine.
315 "%s: Error: CMOS checksum is not byte-aligned.\n",
321 index2
= index
+ 1; /* The CMOS checksum occupies 16 bits. */
323 if (verify_cmos_byte_index(index
) || verify_cmos_byte_index(index2
)) {
325 "%s: Error: CMOS checksum location out of range.\n",
330 if (((index
>= cmos_checksum_start
) && (index
<= cmos_checksum_end
)) ||
331 (((index2
) >= cmos_checksum_start
)
332 && ((index2
) <= cmos_checksum_end
))) {
334 "%s: Error: CMOS checksum overlaps checksummed area.\n",
339 cmos_checksum_index
= index
;
342 /****************************************************************************
343 * try_convert_checksum_layout
345 * Perform sanity checking on CMOS checksum layout information and attempt to
346 * convert information from bit positions to byte positions. Return OK on
347 * success or an error code on failure.
348 ****************************************************************************/
349 static void try_convert_checksum_layout(cmos_checksum_layout_t
* layout
)
351 switch (checksum_layout_to_bytes(layout
)) {
355 case LAYOUT_SUMMED_AREA_START_NOT_ALIGNED
:
357 "%s: CMOS checksummed area start is not byte-aligned.\n",
361 case LAYOUT_SUMMED_AREA_END_NOT_ALIGNED
:
363 "%s: CMOS checksummed area end is not byte-aligned.\n",
367 case LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED
:
369 "%s: CMOS checksum location is not byte-aligned.\n",
373 case LAYOUT_INVALID_SUMMED_AREA
:
375 "%s: CMOS checksummed area end must be greater than "
376 "CMOS checksummed area start.\n", prog_name
);
379 case LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA
:
381 "%s: CMOS checksum overlaps checksummed area.\n",
385 case LAYOUT_SUMMED_AREA_OUT_OF_RANGE
:
387 "%s: CMOS checksummed area out of range.\n", prog_name
);
390 case LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE
:
392 "%s: CMOS checksum location out of range.\n",
403 /****************************************************************************
404 * try_add_cmos_table_enum
406 * Attempt to add a CMOS enum to our internal repository. Exit with an error
407 * message on failure.
408 ****************************************************************************/
409 static void try_add_cmos_table_enum(cmos_enum_t
* cmos_enum
)
411 switch (add_cmos_enum(cmos_enum
)) {
415 case LAYOUT_DUPLICATE_ENUM
:
416 fprintf(stderr
, "%s: Duplicate enum %s found in CMOS option "
417 "table.\n", prog_name
, cmos_enum
->text
);
427 /****************************************************************************
428 * try_add_cmos_table_entry
430 * Attempt to add a CMOS entry to our internal repository. Exit with an
431 * error message on failure.
432 ****************************************************************************/
433 static void try_add_cmos_table_entry(cmos_entry_t
* cmos_entry
)
435 const cmos_entry_t
*conflict
;
437 switch (add_cmos_entry(cmos_entry
, &conflict
)) {
441 case CMOS_AREA_OUT_OF_RANGE
:
443 "%s: Bad CMOS option layout in CMOS option table entry "
444 "%s.\n", prog_name
, cmos_entry
->name
);
447 case CMOS_AREA_TOO_WIDE
:
449 "%s: Area too wide for CMOS option table entry %s.\n",
450 prog_name
, cmos_entry
->name
);
453 case LAYOUT_ENTRY_OVERLAP
:
455 "%s: CMOS option table entries %s and %s have overlapping "
456 "layouts.\n", prog_name
, cmos_entry
->name
,
460 case LAYOUT_ENTRY_BAD_LENGTH
:
461 /* Silently ignore entries with zero length. Although this should
462 * never happen in practice, we should handle the case in a
463 * reasonable manner just to be safe.
467 case LAYOUT_MULTIBYTE_ENTRY_NOT_ALIGNED
:
469 "%s: Unaligned CMOS option table entry %s "
470 "spans multiple bytes.\n", prog_name
, cmos_entry
->name
);
480 /****************************************************************************
481 * first_cmos_table_entry
483 * Return a pointer to the first entry in the CMOS table that represents a
484 * CMOS parameter. Return NULL if CMOS table is empty.
485 ****************************************************************************/
486 static const struct cmos_entries
*first_cmos_table_entry(void)
488 return (const struct cmos_entries
*)first_cmos_rec(LB_TAG_OPTION
);
491 /****************************************************************************
492 * next_cmos_table_entry
494 * Return a pointer to the next entry after 'last' in the CMOS table that
495 * represents a CMOS parameter. Return NULL if there are no more parameters.
496 ****************************************************************************/
497 static const struct cmos_entries
*next_cmos_table_entry(const struct
500 return (const struct cmos_entries
*)
501 next_cmos_rec((const struct lb_record
*)last
, LB_TAG_OPTION
);
504 /****************************************************************************
505 * first_cmos_table_enum
507 * Return a pointer to the first entry in the CMOS table that represents a
508 * possible CMOS parameter value. Return NULL if the table does not contain
510 ****************************************************************************/
511 static const struct cmos_enums
*first_cmos_table_enum(void)
513 return (const struct cmos_enums
*)first_cmos_rec(LB_TAG_OPTION_ENUM
);
516 /****************************************************************************
517 * next_cmos_table_enum
519 * Return a pointer to the next entry after 'last' in the CMOS table that
520 * represents a possible CMOS parameter value. Return NULL if there are no
521 * more parameter values.
522 ****************************************************************************/
523 static const struct cmos_enums
*next_cmos_table_enum
524 (const struct cmos_enums
*last
) {
525 return (const struct cmos_enums
*)
526 next_cmos_rec((const struct lb_record
*)last
, LB_TAG_OPTION_ENUM
);
529 /****************************************************************************
532 * Return a pointer to the first entry in the CMOS table whose type matches
533 * 'tag'. Return NULL if CMOS table contains no such entry.
535 * Possible values for 'tag' are as follows:
537 * LB_TAG_OPTION: The entry represents a CMOS parameter.
538 * LB_TAG_OPTION_ENUM: The entry represents a possible value for a CMOS
539 * parameter of type 'enum'.
541 * The CMOS table tells us where in the nonvolatile RAM to look for CMOS
542 * parameter values and specifies their types as 'enum', 'hex', or
544 ****************************************************************************/
545 static const struct lb_record
*first_cmos_rec(uint32_t tag
)
548 uint32_t bytes_processed
, bytes_for_entries
;
549 const struct lb_record
*lbrec
;
551 p
= ((const char *)cmos_table
) + cmos_table
->header_length
;
552 bytes_for_entries
= cmos_table
->size
- cmos_table
->header_length
;
554 for (bytes_processed
= 0;
555 bytes_processed
< bytes_for_entries
;
556 bytes_processed
+= lbrec
->size
) {
557 lbrec
= (const struct lb_record
*)&p
[bytes_processed
];
559 if (lbrec
->tag
== tag
)
566 /****************************************************************************
569 * Return a pointer to the next entry after 'last' in the CMOS table whose
570 * type matches 'tag'. Return NULL if the table contains no more entries of
572 ****************************************************************************/
573 static const struct lb_record
*next_cmos_rec(const struct lb_record
*last
,
577 uint32_t bytes_processed
, bytes_for_entries
, last_offset
;
578 const struct lb_record
*lbrec
;
580 p
= ((const char *)cmos_table
) + cmos_table
->header_length
;
581 bytes_for_entries
= cmos_table
->size
- cmos_table
->header_length
;
582 last_offset
= ((const char *)last
) - p
;
584 for (bytes_processed
= last_offset
+ last
->size
;
585 bytes_processed
< bytes_for_entries
;
586 bytes_processed
+= lbrec
->size
) {
587 lbrec
= (const struct lb_record
*)&p
[bytes_processed
];
589 if (lbrec
->tag
== tag
)