/**************************************************************************** * get_cmos_checksum_info * * Get layout information for CMOS checksum. ****************************************************************************/ static void get_cmos_checksum_info(void) { const cmos_entry_t *e; struct cmos_checksum *checksum; cmos_checksum_layout_t layout; unsigned index, index2; checksum = (struct cmos_checksum *)next_cmos_rec((const struct lb_record *)first_cmos_table_enum(), LB_TAG_OPTION_CHECKSUM); if (checksum != NULL) { /* We are lucky. The coreboot table hints us to the checksum. * We might have to check the type field here though. */ layout.summed_area_start = checksum->range_start; layout.summed_area_end = checksum->range_end; layout.checksum_at = checksum->location; try_convert_checksum_layout(&layout); cmos_checksum_start = layout.summed_area_start; cmos_checksum_end = layout.summed_area_end; cmos_checksum_index = layout.checksum_at; return; } if ((e = find_cmos_entry(checksum_param_name)) == NULL) return; /* If we get here, we are unlucky. The CMOS option table contains the * location of the CMOS checksum. However, there is no information * regarding which bytes of the CMOS area the checksum is computed over. * Thus we have to hope our presets will be fine. */ if (e->bit % 8) { fprintf(stderr, "%s: Error: CMOS checksum is not byte-aligned.\n", prog_name); exit(1); } index = e->bit / 8; index2 = index + 1; /* The CMOS checksum occupies 16 bits. */ if (verify_cmos_byte_index(index) || verify_cmos_byte_index(index2)) { fprintf(stderr, "%s: Error: CMOS checksum location out of range.\n", prog_name); exit(1); } if (((index >= cmos_checksum_start) && (index <= cmos_checksum_end)) || (((index2) >= cmos_checksum_start) && ((index2) <= cmos_checksum_end))) { fprintf(stderr, "%s: Error: CMOS checksum overlaps checksummed area.\n", prog_name); exit(1); } cmos_checksum_index = index; }
/**************************************************************************** * list_one_param * * Attempt to list one CMOS parameter given by 'name'. 'show_name' is a * boolean value indicating whether the parameter name should be displayed * along with its value. Return 1 if error was encountered. Else return OK. ****************************************************************************/ static int list_one_param(const char name[], int show_name) { const cmos_entry_t *e; if (is_checksum_name(name) || ((e = find_cmos_entry(name)) == NULL)) { fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, name); exit(1); } if (e->config == CMOS_ENTRY_RESERVED) { fprintf(stderr, "%s: Parameter %s is reserved.\n", prog_name, name); exit(1); } return (list_cmos_entry(e, show_name) != 0); }
/**************************************************************************** * list_param_enums * * List all possible values for CMOS parameter given by 'name'. ****************************************************************************/ static void list_param_enums(const char name[]) { const cmos_entry_t *e; const cmos_enum_t *p; if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) { fprintf(stderr, "%s: CMOS parameter %s not found.\n", prog_name, name); exit(1); } switch (e->config) { case CMOS_ENTRY_ENUM: for (p = first_cmos_enum_id(e->config_id); p != NULL; p = next_cmos_enum_id(p)) printf("%s\n", p->text); break; case CMOS_ENTRY_HEX: printf("Parameter %s requires a %u-bit unsigned integer.\n", name, e->length); break; case CMOS_ENTRY_STRING: printf("Parameter %s requires a %u-byte string.\n", name, e->length / 8); break; case CMOS_ENTRY_RESERVED: printf("Parameter %s is reserved.\n", name); break; default: BUG(); } }
/**************************************************************************** * process_input_file * * Read the contents of file 'f' and return a pointer to a list of pending * write operations. Perform sanity checking on all write operations and * exit with an error message if there is a problem. ****************************************************************************/ cmos_write_t *process_input_file(FILE * f) { static const int LINE_BUF_SIZE = 256; static const size_t N_MATCHES = 4; char line[LINE_BUF_SIZE]; const char *name, *value; cmos_write_t *list, *item, **p; regex_t blank_or_comment, assignment; regmatch_t match[N_MATCHES]; const cmos_entry_t *e; list = NULL; p = &list; compile_reg_expr(REG_EXTENDED | REG_NEWLINE, blank_or_comment_regex, &blank_or_comment); compile_reg_expr(REG_EXTENDED | REG_NEWLINE, assignment_regex, &assignment); /* each iteration processes one line from input file */ for (line_num = 1; get_input_file_line(f, line, LINE_BUF_SIZE) == OK; line_num++) { /* skip comments and blank lines */ if (!regexec(&blank_or_comment, line, 0, NULL, 0)) continue; /* Is this a valid assignment line? If not, then it's a syntax * error. */ if (regexec(&assignment, line, N_MATCHES, match, 0)) { fprintf(stderr, "%s: Syntax error on line %d of input file.\n", prog_name, line_num); exit(1); } /* OK, we found an assignment. Break the line into substrings * representing the lefthand and righthand sides of the assignment. */ line[match[1].rm_eo] = '\0'; line[match[2].rm_eo] = '\0'; name = &line[match[1].rm_so]; value = &line[match[2].rm_so]; /* now look up the coreboot parameter name */ if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) { fprintf(stderr, "%s: Error on line %d of input file: CMOS parameter " "%s not found.\n", prog_name, line_num, name); exit(1); } /* At this point, we figure out what numeric value needs to be written * to which location. At the same time, we perform sanity checking on * the write operation. */ if ((item = (cmos_write_t *) malloc(sizeof(*item))) == NULL) out_of_memory(); item->bit = e->bit; item->length = e->length; item->config = e->config; item->value = try_prepare_cmos_write(e, value); /* Append write operation to pending write list. */ item->next = NULL; *p = item; p = &item->next; } regfree(&blank_or_comment); regfree(&assignment); return list; }
/**************************************************************************** * set_one_param * * Set the CMOS parameter given by 'name' to 'value'. The 'name' parameter * is case-sensitive. If we are setting an enum parameter, then 'value' is * interpreted as a case-sensitive string that must match the option name * exactly. If we are setting a 'hex' parameter, then 'value' is treated as * a string representation of an unsigned integer that may be specified in * decimal, hex, or octal. ****************************************************************************/ static void set_one_param(const char name[], const char value[]) { const cmos_entry_t *e; unsigned long long n; if (is_checksum_name(name) || (e = find_cmos_entry(name)) == NULL) { fprintf(stderr, "%s: CMOS parameter %s not found.", prog_name, name); exit(1); } switch (prepare_cmos_write(e, value, &n)) { case OK: break; case CMOS_OP_BAD_ENUM_VALUE: fprintf(stderr, "%s: Bad value for parameter %s.", prog_name, name); goto fail; case CMOS_OP_NEGATIVE_INT: fprintf(stderr, "%s: This program does not support assignment of negative " "numbers to coreboot parameters.", prog_name); goto fail; case CMOS_OP_INVALID_INT: fprintf(stderr, "%s: %s is not a valid integer.", prog_name, value); goto fail; case CMOS_OP_RESERVED: fprintf(stderr, "%s: Can not modify reserved coreboot parameter %s.", prog_name, name); goto fail; case CMOS_OP_VALUE_TOO_WIDE: fprintf(stderr, "%s: Can not write value %s to CMOS parameter %s that is " "only %d bits wide.", prog_name, value, name, e->length); goto fail; case CMOS_OP_NO_MATCHING_ENUM: fprintf(stderr, "%s: coreboot parameter %s has no matching enums.", prog_name, name); goto fail; case CMOS_AREA_OUT_OF_RANGE: fprintf(stderr, "%s: The CMOS area specified by the layout info for " "coreboot parameter %s is out of range.", prog_name, name); goto fail; case CMOS_AREA_OVERLAPS_RTC: fprintf(stderr, "%s: The CMOS area specified by the layout info for " "coreboot parameter %s overlaps the realtime clock area.", prog_name, name); goto fail; case CMOS_AREA_TOO_WIDE: fprintf(stderr, "%s: The CMOS area specified by the layout info for " "coreboot parameter %s is too wide.", prog_name, name); goto fail; default: fprintf(stderr, "%s: Unknown error encountered while attempting to modify " "coreboot parameter %s.", prog_name, name); goto fail; } /* write the value to nonvolatile RAM */ set_iopl(3); cmos_write(e, n); cmos_checksum_write(cmos_checksum_compute()); set_iopl(0); return; fail: fprintf(stderr, " CMOS write not performed.\n"); exit(1); }