nvramtool.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <fcntl.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #ifndef __MINGW32__ 7 #include <sys/mman.h> 8 #endif 9 #include "common.h" 10 #include "opts.h" 11 #include "lbtable.h" 12 #include "layout.h" 13 #include "accessors/layout-text.h" 14 #include "input_file.h" 15 #include "cmos_ops.h" 16 #include "cmos_lowlevel.h" 17 #include "reg_expr.h" 18 #include "hexdump.h" 19 #include "cbfs.h" 20 #ifdef __MINGW32__ 21 #include <windows.h> 22 #endif 23 24 typedef void (*op_fn_t) (void); 25 26 static void op_show_version(void); 27 static void op_show_usage(void); 28 static void op_lbtable_show_info(void); 29 static void op_lbtable_dump(void); 30 static void op_show_param_values(void); 31 static void op_cmos_show_one_param(void); 32 static void op_cmos_show_all_params(void); 33 static void op_cmos_set_one_param(void); 34 static void op_cmos_set_params_stdin(void); 35 static void op_cmos_set_params_file(void); 36 static void op_cmos_checksum(void); 37 static void op_show_layout(void); 38 static void op_write_cmos_dump(void); 39 static void op_read_cmos_dump(void); 40 static void op_show_cmos_hex_dump(void); 41 static void op_show_cmos_dumpfile(void); 42 static void op_write_cmos_layout_bin(void); 43 static void op_write_cmos_layout_header(void); 44 static int list_one_param(const char name[], int show_name); 45 static int list_all_params(void); 46 static void list_param_enums(const char name[]); 47 static void set_one_param(const char name[], const char value[]); 48 static void set_params(FILE * f); 49 static void parse_assignment(char arg[], const char **name, const char **value); 50 static int list_cmos_entry(const cmos_entry_t * e, int show_name); 51 static uint16_t convert_checksum_value(const char value[]); 52 53 static const op_fn_t op_fns[] = { op_show_version, 54 op_show_usage, 55 op_lbtable_show_info, 56 op_lbtable_dump, 57 op_show_param_values, 58 op_cmos_show_one_param, 59 op_cmos_show_all_params, 60 op_cmos_set_one_param, 61 op_cmos_set_params_stdin, 62 op_cmos_set_params_file, 63 op_cmos_checksum, 64 op_show_layout, 65 op_write_cmos_dump, 66 op_read_cmos_dump, 67 op_show_cmos_hex_dump, 68 op_show_cmos_dumpfile, 69 op_write_cmos_layout_bin, 70 op_write_cmos_layout_header 71 }; 72 73 static void op_write_cmos_layout_bin(void) 74 { 75 get_layout_from_file(); 76 write_cmos_output_bin(nvramtool_op.param); 77 } 78 79 static void op_write_cmos_layout_header(void) 80 { 81 get_layout_from_file(); 82 write_cmos_layout_header(nvramtool_op.param); 83 } 84 85 static const hexdump_format_t cmos_dump_format = 86 { 16, 2, "", " | ", " ", " | ", '.' }; 87 88 /**************************************************************************** 89 * main 90 ****************************************************************************/ 91 int main(int argc, char *argv[]) 92 { 93 void *cmos_default = NULL; 94 cmos_layout_get_fn_t fn = get_layout_from_cmos_table; 95 96 parse_nvramtool_args(argc, argv); 97 98 /* If we should operate on a CBFS file default to reading the layout 99 * and CMOS contents from it. */ 100 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].found) { 101 open_cbfs(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CBFS_FILE].param); 102 if (!nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) { 103 cmos_default = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT, NULL); 104 if (cmos_default == NULL) { 105 fprintf(stderr, "Need a cmos.default in the CBFS image or separate CMOS file (-D).\n"); 106 exit(1); 107 } 108 } 109 fn = get_layout_from_cbfs_file; 110 } 111 112 /* If the user wants to use a specific layout file or explicitly use 113 * the coreboot option table allow him to override previous settings. */ 114 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].found) { 115 set_layout_filename(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_LAYOUT_FILE].param); 116 fn = get_layout_from_file; 117 } else if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_OPT_TABLE].found) { 118 fn = get_layout_from_cmos_table; 119 } 120 121 /* Allow the user to use a file for the CMOS contents, possibly 122 * overriding a previously opened "cmos.default" file from the CBFS. */ 123 if (nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].found) { 124 struct stat fd_stat; 125 int fd; 126 127 if ((fd = open(nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param, O_RDWR | O_CREAT, 0666)) < 0) { 128 fprintf(stderr, "Couldn't open '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param); 129 exit(1); 130 } 131 132 if (fstat(fd, &fd_stat) == -1) { 133 fprintf(stderr, "Couldn't stat '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param); 134 exit(1); 135 } 136 137 if (fd_stat.st_size < CMOS_SIZE) { 138 if ((lseek(fd, CMOS_SIZE - 1, SEEK_SET) == -1) || 139 (write(fd, "\0", 1) != 1)) { 140 fprintf(stderr, "Unable to extended '%s' to its full size.\n", 141 nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param); 142 exit(1); 143 } 144 #ifndef __MINGW32__ 145 fsync(fd); 146 #else 147 FlushFileBuffers ((HANDLE) _get_osfhandle (fd)); 148 #endif 149 } 150 151 cmos_default = mmap(NULL, CMOS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 152 if (cmos_default == MAP_FAILED) { 153 fprintf(stderr, "Couldn't map '%s'\n", nvramtool_op_modifiers[NVRAMTOOL_MOD_USE_CMOS_FILE].param); 154 exit(1); 155 } 156 } 157 158 /* Switch to memory based CMOS access. */ 159 if (cmos_default) { 160 select_hal(HAL_MEMORY, cmos_default); 161 } 162 163 register_cmos_layout_get_fn(fn); 164 op_fns[nvramtool_op.op](); 165 166 return 0; 167 } 168 169 /**************************************************************************** 170 * op_show_version 171 * 172 * -v 173 * 174 * Show version information for this program. 175 ****************************************************************************/ 176 static void op_show_version(void) 177 { 178 printf("This is %s version %s.\n", prog_name, prog_version); 179 } 180 181 /**************************************************************************** 182 * op_show_usage 183 * 184 * -h 185 * 186 * Show a usage message for this program. 187 ****************************************************************************/ 188 static void op_show_usage(void) 189 { 190 usage(stdout); 191 } 192 193 /**************************************************************************** 194 * op_lbtable_show_info 195 * 196 * -l [ARG] 197 * 198 * If ARG is present, show coreboot table information specified by ARG. 199 * Else show all possible values for ARG. 200 ****************************************************************************/ 201 static void op_lbtable_show_info(void) 202 { 203 if (nvramtool_op.param == NULL) 204 list_lbtable_choices(); 205 else { 206 get_lbtable(); 207 list_lbtable_item(nvramtool_op.param); 208 } 209 } 210 211 /**************************************************************************** 212 * op_lbtable_dump 213 * 214 * -d 215 * 216 * Do low-level dump of coreboot table. 217 ****************************************************************************/ 218 static void op_lbtable_dump(void) 219 { 220 get_lbtable(); 221 dump_lbtable(); 222 } 223 224 /**************************************************************************** 225 * op_show_param_values 226 * 227 * -e NAME option 228 * 229 * Show all possible values for parameter NAME. 230 ****************************************************************************/ 231 static void op_show_param_values(void) 232 { 233 get_cmos_layout(); 234 list_param_enums(nvramtool_op.param); 235 } 236 237 /**************************************************************************** 238 * op_cmos_show_one_param 239 * 240 * [-n] -r NAME 241 * 242 * Show parameter NAME. If -n is specified, show value only. Else show name 243 * and value. 244 ****************************************************************************/ 245 static void op_cmos_show_one_param(void) 246 { 247 int result; 248 249 get_cmos_layout(); 250 result = list_one_param(nvramtool_op.param, 251 !nvramtool_op_modifiers 252 [NVRAMTOOL_MOD_SHOW_VALUE_ONLY].found); 253 cmos_checksum_verify(); 254 255 if (result) 256 exit(1); 257 } 258 259 /**************************************************************************** 260 * op_cmos_show_all_params 261 * 262 * -a 263 * 264 * Show names and values for all parameters. 265 ****************************************************************************/ 266 static void op_cmos_show_all_params(void) 267 { 268 int result; 269 270 get_cmos_layout(); 271 result = list_all_params(); 272 cmos_checksum_verify(); 273 274 if (result) 275 exit(1); 276 } 277 278 /**************************************************************************** 279 * op_cmos_set_one_param 280 * 281 * -w NAME=VALUE 282 * 283 * Set parameter NAME to VALUE. 284 ****************************************************************************/ 285 static void op_cmos_set_one_param(void) 286 { 287 const char *name, *value; 288 289 get_cmos_layout(); 290 291 /* Separate 'NAME=VALUE' syntax into two strings representing NAME and 292 * VALUE. 293 */ 294 parse_assignment(nvramtool_op.param, &name, &value); 295 296 set_one_param(name, value); 297 } 298 299 /**************************************************************************** 300 * op_cmos_set_params_stdin 301 * 302 * -i 303 * 304 * Set parameters according to standard input. 305 ****************************************************************************/ 306 static void op_cmos_set_params_stdin(void) 307 { 308 get_cmos_layout(); 309 set_params(stdin); 310 } 311 312 /**************************************************************************** 313 * op_cmos_set_params_file 314 * 315 * -p INPUT_FILE 316 * 317 * Set parameters according to INPUT_FILE. 318 ****************************************************************************/ 319 static void op_cmos_set_params_file(void) 320 { 321 FILE *f; 322 323 if ((f = fopen(nvramtool_op.param, "r")) == NULL) { 324 fprintf(stderr, "%s: Can not open file %s for reading: %s\n", 325 prog_name, nvramtool_op.param, strerror(errno)); 326 exit(1); 327 } 328 329 get_cmos_layout(); 330 set_params(f); 331 fclose(f); 332 } 333 334 /**************************************************************************** 335 * op_cmos_checksum 336 * 337 * -c [VALUE] 338 * 339 * If VALUE is present, set coreboot CMOS checksum to VALUE. Else show 340 * checksum value. 341 ****************************************************************************/ 342 static void op_cmos_checksum(void) 343 { 344 uint16_t checksum; 345 346 get_cmos_layout(); 347 348 if (nvramtool_op.param == NULL) { 349 set_iopl(3); 350 checksum = cmos_checksum_read(); 351 set_iopl(0); 352 printf("0x%x\n", checksum); 353 } else { 354 checksum = convert_checksum_value(nvramtool_op.param); 355 set_iopl(3); 356 cmos_checksum_write(checksum); 357 set_iopl(0); 358 } 359 } 360 361 /**************************************************************************** 362 * op_show_layout 363 * 364 * -Y 365 * 366 * Write CMOS layout information to standard output. 367 ****************************************************************************/ 368 static void op_show_layout(void) 369 { 370 get_cmos_layout(); 371 write_cmos_layout(stdout); 372 } 373 374 /**************************************************************************** 375 * op_write_cmos_dump 376 * 377 * -b OUTPUT_FILE 378 * 379 * Write the contents of CMOS memory to a binary file. 380 ****************************************************************************/ 381 static void op_write_cmos_dump(void) 382 { 383 unsigned char data[CMOS_SIZE]; 384 FILE *f; 385 386 if ((f = fopen(nvramtool_op.param, "wb")) == NULL) { 387 fprintf(stderr, "%s: Can not open file %s for writing: %s\n", 388 prog_name, nvramtool_op.param, strerror(errno)); 389 exit(1); 390 } 391 392 set_iopl(3); 393 cmos_read_all(data); 394 set_iopl(0); 395 396 if (fwrite(data, 1, CMOS_SIZE, f) != CMOS_SIZE) { 397 fprintf(stderr, "%s: Error writing CMOS data to file %s: %s\n", 398 prog_name, nvramtool_op.param, strerror(errno)); 399 exit(1); 400 } 401 402 fclose(f); 403 } 404 405 /**************************************************************************** 406 * op_read_cmos_dump 407 * 408 * -B INPUT_FILE 409 * 410 * Read binary data from a file and write the data to CMOS memory. 411 ****************************************************************************/ 412 static void op_read_cmos_dump(void) 413 { 414 unsigned char data[CMOS_SIZE]; 415 size_t nr_bytes; 416 FILE *f; 417 418 if ((f = fopen(nvramtool_op.param, "rb")) == NULL) { 419 fprintf(stderr, "%s: Can not open file %s for reading: %s\n", 420 prog_name, nvramtool_op.param, strerror(errno)); 421 exit(1); 422 } 423 424 if ((nr_bytes = fread(data, 1, CMOS_SIZE, f)) != CMOS_SIZE) { 425 fprintf(stderr, 426 "%s: Error: Only able to read %d bytes of CMOS data " 427 "from file %s. CMOS data is unchanged.\n", prog_name, 428 (int)nr_bytes, nvramtool_op.param); 429 exit(1); 430 } 431 432 fclose(f); 433 set_iopl(3); 434 cmos_write_all(data); 435 set_iopl(0); 436 } 437 438 /**************************************************************************** 439 * op_show_cmos_hex_dump 440 * 441 * -x 442 * 443 * Write a hex dump of CMOS memory to standard output. 444 ****************************************************************************/ 445 static void op_show_cmos_hex_dump(void) 446 { 447 unsigned char data[CMOS_SIZE]; 448 449 set_iopl(3); 450 cmos_read_all(data); 451 set_iopl(0); 452 hexdump(data, CMOS_SIZE, 0, stdout, &cmos_dump_format); 453 } 454 455 /**************************************************************************** 456 * op_show_cmos_dumpfile 457 * 458 * -X DUMP_FILE 459 * 460 * Read binary data from a file (presumably a CMOS dump file) and display a 461 * hex dump of the CMOS data from the file. 462 ****************************************************************************/ 463 static void op_show_cmos_dumpfile(void) 464 { 465 unsigned char data[CMOS_SIZE]; 466 size_t nr_bytes; 467 FILE *f; 468 469 if ((f = fopen(nvramtool_op.param, "r")) == NULL) { 470 fprintf(stderr, "%s: Can not open file %s for reading: %s\n", 471 prog_name, nvramtool_op.param, strerror(errno)); 472 exit(1); 473 } 474 475 nr_bytes = fread(data, 1, CMOS_SIZE, f); 476 fclose(f); 477 hexdump(data, nr_bytes, 0, stdout, &cmos_dump_format); 478 } 479 480 /**************************************************************************** 481 * list_one_param 482 * 483 * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a 484 * boolean value indicating whether the parameter name should be displayed 485 * along with its value. Return 1 if error was encountered. Else return OK. 486 ****************************************************************************/ 487 static int list_one_param(const char name[], int show_name) 488 { 489 const cmos_entry_t *e; 490 491 if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) { 492 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, 493 name); 494 exit(1); 495 } 496 497 if (e->config == CMOS_ENTRY_RESERVED) { 498 fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name, 499 name); 500 exit(1); 501 } 502 503 return (list_cmos_entry(e, show_name) != 0); 504 } 505 506 /**************************************************************************** 507 * list_all_params 508 * 509 * Attempt to list all CMOS parameters. Return 1 if error was encountered. 510 * Else return OK. 511 ****************************************************************************/ 512 static int list_all_params(void) 513 { 514 const cmos_entry_t *e; 515 int result; 516 517 result = OK; 518 519 for (e = first_cmos_entry(); e != NULL; e = next_cmos_entry(e)) { 520 if ((e->config == CMOS_ENTRY_RESERVED) 521 || is_checksum_name(e->name)) 522 continue; 523 524 if (list_cmos_entry(e, TRUE)) 525 result = 1; 526 } 527 528 return result; 529 } 530 531 /**************************************************************************** 532 * list_param_enums 533 * 534 * List all possible values for CMOS parameter given by 'name'. 535 ****************************************************************************/ 536 static void list_param_enums(const char name[]) 537 { 538 const cmos_entry_t *e; 539 const cmos_enum_t *p; 540 541 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) { 542 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, 543 name); 544 exit(1); 545 } 546 547 switch (e->config) { 548 case CMOS_ENTRY_ENUM: 549 for (p = first_cmos_enum_id(e->config_id); 550 p != NULL; p = next_cmos_enum_id(p)) 551 printf("%s\n", p->text); 552 553 break; 554 555 case CMOS_ENTRY_HEX: 556 printf("Parameter %s requires a %u-bit unsigned integer.\n", 557 name, e->length); 558 break; 559 560 case CMOS_ENTRY_STRING: 561 printf("Parameter %s requires a %u-byte string.\n", name, 562 e->length / 8); 563 break; 564 565 case CMOS_ENTRY_RESERVED: 566 printf("Parameter %s is reserved.\n", name); 567 break; 568 569 default: 570 BUG(); 571 } 572 } 573 574 /**************************************************************************** 575 * set_one_param 576 * 577 * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter 578 * is case-sensitive. If we are setting an enum parameter, then 'value' is 579 * interpreted as a case-sensitive string that must match the option name 580 * exactly. If we are setting a 'hex' parameter, then 'value' is treated as 581 * a string representation of an unsigned integer that may be specified in 582 * decimal, hex, or octal. 583 ****************************************************************************/ 584 static void set_one_param(const char name[], const char value[]) 585 { 586 const cmos_entry_t *e; 587 unsigned long long n; 588 589 if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) { 590 fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, 591 name); 592 exit(1); 593 } 594 595 switch (prepare_cmos_write(e, value, &n)) { 596 case OK: 597 break; 598 599 case CMOS_OP_BAD_ENUM_VALUE: 600 fprintf(stderr, "%s: Bad value for parameter %s.", prog_name, 601 name); 602 goto fail; 603 604 case CMOS_OP_NEGATIVE_INT: 605 fprintf(stderr, 606 "%s: This program does not support assignment of negative " 607 "numbers to coreboot parameters.", prog_name); 608 goto fail; 609 610 case CMOS_OP_INVALID_INT: 611 fprintf(stderr, "%s: %s is not a valid integer.", prog_name, 612 value); 613 goto fail; 614 615 case CMOS_OP_RESERVED: 616 fprintf(stderr, 617 "%s: Can not modify reserved coreboot parameter %s.", 618 prog_name, name); 619 goto fail; 620 621 case CMOS_OP_VALUE_TOO_WIDE: 622 fprintf(stderr, 623 "%s: Can not write value %s to CMOS parameter %s that is " 624 "only %d bits wide.", prog_name, value, name, 625 e->length); 626 goto fail; 627 628 case CMOS_OP_NO_MATCHING_ENUM: 629 fprintf(stderr, 630 "%s: coreboot parameter %s has no matching enums.", 631 prog_name, name); 632 goto fail; 633 634 case CMOS_AREA_OUT_OF_RANGE: 635 fprintf(stderr, 636 "%s: The CMOS area specified by the layout info for " 637 "coreboot parameter %s is out of range.", prog_name, 638 name); 639 goto fail; 640 641 case CMOS_AREA_OVERLAPS_RTC: 642 fprintf(stderr, 643 "%s: The CMOS area specified by the layout info for " 644 "coreboot parameter %s overlaps the realtime clock area.", 645 prog_name, name); 646 goto fail; 647 648 case CMOS_AREA_TOO_WIDE: 649 fprintf(stderr, 650 "%s: The CMOS area specified by the layout info for " 651 "coreboot parameter %s is too wide.", prog_name, name); 652 goto fail; 653 654 default: 655 fprintf(stderr, 656 "%s: Unknown error encountered while attempting to modify " 657 "coreboot parameter %s.", prog_name, name); 658 goto fail; 659 } 660 661 /* write the value to nonvolatile RAM */ 662 set_iopl(3); 663 cmos_write(e, n); 664 cmos_checksum_write(cmos_checksum_compute()); 665 set_iopl(0); 666 return; 667 668 fail: 669 fprintf(stderr, " CMOS write not performed.\n"); 670 exit(1); 671 } 672 673 /**************************************************************************** 674 * set_params 675 * 676 * Set coreboot parameters according to the contents of file 'f'. 677 ****************************************************************************/ 678 static void set_params(FILE * f) 679 { /* First process the input file. Then perform writes only if there were 680 * no problems processing the input. Either all values will be written 681 * successfully or no values will be written. 682 */ 683 do_cmos_writes(process_input_file(f)); 684 } 685 686 /**************************************************************************** 687 * parse_assignment 688 * 689 * Parse the string 'arg' (which supposedly represents an assignment) into a 690 * NAME and a VALUE. If 'arg' does not conform to the proper assignment 691 * syntax, exit with a usage message. Otherwise, on return, 'arg' is broken 692 * into substrings representing NAME and VALUE, and *name and *value are set 693 * to point to these two substrings. 694 ****************************************************************************/ 695 static void parse_assignment(char arg[], const char **name, const char **value) 696 { 697 static const size_t N_MATCHES = 4; 698 regmatch_t match[N_MATCHES]; 699 regex_t assignment; 700 701 compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment); 702 703 /* Does 'arg' conform to proper assignment syntax? If not, exit with a 704 * usage message. 705 */ 706 if (regexec(&assignment, arg, N_MATCHES, match, 0)) 707 usage(stderr); 708 709 /* Ok, we found a valid assignment. Break it into two strings 710 * representing NAME and VALUE. 711 */ 712 arg[match[1].rm_eo] = '\0'; 713 arg[match[2].rm_eo] = '\0'; 714 *name = &arg[match[1].rm_so]; 715 *value = &arg[match[2].rm_so]; 716 717 regfree(&assignment); 718 } 719 720 /**************************************************************************** 721 * list_cmos_entry 722 * 723 * Attempt to list the CMOS entry represented by 'e'. 'show_name' is a 724 * boolean value indicating whether the parameter name should be displayed 725 * along with its value. On success, return OK. On error, print an error 726 * message and return 1. 727 ****************************************************************************/ 728 static int list_cmos_entry(const cmos_entry_t * e, int show_name) 729 { 730 const cmos_enum_t *p; 731 unsigned long long value; 732 char *w; 733 734 /* sanity check CMOS entry */ 735 switch (prepare_cmos_read(e)) { 736 case OK: 737 break; 738 739 case CMOS_OP_RESERVED: 740 fprintf(stderr, 741 "%s: Cannot access reserved CMOS area (for %s).\n", 742 prog_name, e->name); 743 return 1; 744 745 case CMOS_AREA_OUT_OF_RANGE: 746 fprintf(stderr, 747 "%s: Can not read coreboot parameter %s because " 748 "layout info specifies out of range CMOS area.\n", 749 prog_name, e->name); 750 return 1; 751 752 case CMOS_AREA_OVERLAPS_RTC: 753 fprintf(stderr, 754 "%s: Can not read coreboot parameter %s because " 755 "layout info specifies CMOS area that overlaps realtime " 756 "clock area.\n", prog_name, e->name); 757 return 1; 758 759 case CMOS_AREA_TOO_WIDE: 760 fprintf(stderr, 761 "%s: Can not read coreboot parameter %s because " 762 "layout info specifies CMOS area that is too wide.\n", 763 prog_name, e->name); 764 return 1; 765 766 default: 767 fprintf(stderr, 768 "%s: Unknown error encountered while attempting to " 769 "read coreboot parameter %s\n", prog_name, e->name); 770 return 1; 771 } 772 773 /* read the value from CMOS */ 774 set_iopl(3); 775 value = cmos_read(e); 776 set_iopl(0); 777 778 /* display the value */ 779 switch (e->config) { 780 case CMOS_ENTRY_ENUM: 781 if ((p = find_cmos_enum(e->config_id, value)) == NULL) { 782 if (show_name) 783 printf("# Bad value -> %s = 0x%llx\n", e->name, 784 value); 785 else 786 printf("Bad value -> 0x%llx\n", value); 787 } else { 788 if (show_name) 789 printf("%s = %s\n", e->name, p->text); 790 else 791 printf("%s\n", p->text); 792 } 793 794 break; 795 796 case CMOS_ENTRY_HEX: 797 if (show_name) 798 printf("%s = 0x%llx\n", e->name, value); 799 else 800 printf("0x%llx\n", value); 801 802 break; 803 804 case CMOS_ENTRY_STRING: 805 w = (char *)(unsigned long)value; 806 while (*w) { 807 if(!isprint((int)(unsigned char)*w)) { 808 if (show_name) 809 printf("# Bad value -> %s\n", e->name); 810 else 811 printf("Bad value\n"); 812 break; 813 } 814 w++; 815 } 816 817 if (!*w) { 818 819 if (show_name) 820 printf("%s = %s\n", e->name, 821 (char *)(unsigned long)value); 822 else 823 printf("%s\n", (char *)(unsigned long)value); 824 } 825 826 free((void *)(unsigned long)value); 827 828 break; 829 830 case CMOS_ENTRY_RESERVED: 831 default: 832 BUG(); 833 } 834 835 return OK; 836 } 837 838 /**************************************************************************** 839 * convert_checksum_value 840 * 841 * 'value' is the string representation of a checksum value that the user 842 * wishes to set using the -c option. Convert the string to a 16-bit 843 * unsigned integer and return the result. Exit with an error message if 844 * 'value' is invalid. 845 ****************************************************************************/ 846 static uint16_t convert_checksum_value(const char value[]) 847 { 848 unsigned long n; 849 const char *p; 850 uint16_t result; 851 int negative; 852 853 for (p = value; isspace((int)(unsigned char)*p); p++) ; 854 855 negative = (*p == '-'); 856 n = strtoul(value, (char **)&p, 0); 857 858 if (*p) { 859 fprintf(stderr, 860 "%s: Checksum value %s is not a valid integer.\n", 861 prog_name, value); 862 exit(1); 863 } 864 865 if (negative) { 866 fprintf(stderr, 867 "%s: Checksum must be an unsigned integer.\n", 868 prog_name); 869 exit(1); 870 } 871 872 result = (uint16_t) n; 873 874 if (result != n) { 875 fprintf(stderr, 876 "%s: Checksum value must fit within 16 bits.\n", 877 prog_name); 878 exit(1); 879 } 880 881 return result; 882 }