diff options
-rw-r--r-- | common/ap_ro_integrity_check.c | 101 |
1 files changed, 75 insertions, 26 deletions
diff --git a/common/ap_ro_integrity_check.c b/common/ap_ro_integrity_check.c index d038c320c5..17abeacf70 100644 --- a/common/ap_ro_integrity_check.c +++ b/common/ap_ro_integrity_check.c @@ -258,6 +258,72 @@ static int ap_ro_erase_hash(void) return rv; } +/** + * Write data to the AP RO data space of H1 flash. + * + * @param version the payload version + * @param type payload type + * @param num_ranges number of ranges in the AP RO payload. + * @param data_offset offset to write AP RO data to. It must be in the AP RO + * flash region. + * @param p_data pointer to the saved data. This is used to make sure the + * region is empty. + * @param buf data to write to AP RO flash. + * @param input_size the amount of data to write. + * + * @return ARCVE_OK on success, ARCVE_ALREADY_PROGRAMMED if there's already + * data stored in the region, or ARCVE_FLASH_WRITE_FAILED if writing + * flash failed.. + */ +static enum ap_ro_check_vc_errors write_ap_ro_check_data(uint8_t version, + uint8_t type, + uint16_t num_ranges, + uint32_t data_offset, + uint32_t *p_data, + void *buf, + size_t input_size) +{ + uint32_t i; + struct ap_ro_check_header check_header; + int rv; + size_t prog_size = sizeof(struct ap_ro_check_header) + input_size; + + /* Verify the ap ro data will fit in the ap ro data flash */ + if ((data_offset < h1_flash_offset_) || + ((data_offset + prog_size) > + (h1_flash_offset_ + AP_RO_DATA_SPACE_SIZE))) + return ARCVE_BAD_PAYLOAD_SIZE; + + /* + * If prog_size isn't divisible by 4, then the remaining bytes won't get + * checked. The payload should be divisible by 4. Reject the data if it + * isn't. + */ + if (prog_size % sizeof(uint32_t)) + return ARCVE_BAD_PAYLOAD_SIZE; + /* Verify the entire data region is erased. */ + for (i = 0; i < (prog_size / sizeof(uint32_t)); i++) + if (p_data[i] != ~0) + return ARCVE_ALREADY_PROGRAMMED; + + check_header.version = version; + check_header.type = type; + check_header.num_ranges = num_ranges; + app_compute_hash(buf, input_size, &check_header.checksum, + sizeof(check_header.checksum)); + + flash_open_ro_window(data_offset, prog_size); + rv = flash_physical_write(data_offset, sizeof(check_header), + (char *)&check_header); + if (rv == EC_SUCCESS) + rv = flash_physical_write(data_offset + sizeof(check_header), + input_size, buf); + flash_close_ro_window(); + if (rv != EC_SUCCESS) + return ARCVE_FLASH_WRITE_FAILED; + return ARCVE_OK; +} + /* * Leaving this function available for testing, will not be necessary in prod * signed images. @@ -266,12 +332,10 @@ static enum vendor_cmd_rc vc_seed_ap_ro_check(enum vendor_cmd_cc code, void *buf, size_t input_size, size_t *response_size) { - struct ap_ro_check_header check_header; const struct ap_ro_check_payload *vc_payload = buf; uint32_t vc_num_of_ranges; uint32_t i; uint8_t *response = buf; - size_t prog_size; int rv; *response_size = 1; /* Just in case there is an error. */ @@ -341,30 +405,15 @@ static enum vendor_cmd_rc vc_seed_ap_ro_check(enum vendor_cmd_cc code, } } - prog_size = sizeof(struct ap_ro_check_header) + input_size; - for (i = 0; i < (prog_size / sizeof(uint32_t)); i++) - if (((uint32_t *)p_chk)[i] != ~0) { - *response = ARCVE_ALREADY_PROGRAMMED; - return VENDOR_RC_NOT_ALLOWED; - } - - check_header.version = AP_RO_HASH_LAYOUT_VERSION_1; - check_header.type = AP_RO_HASH_TYPE_FACTORY; - check_header.num_ranges = vc_num_of_ranges; - app_compute_hash(buf, input_size, &check_header.checksum, - sizeof(check_header.checksum)); - - flash_open_ro_window(h1_flash_offset_, prog_size); - rv = flash_physical_write(h1_flash_offset_, sizeof(check_header), - (char *)&check_header); - if (rv == EC_SUCCESS) - rv = flash_physical_write(h1_flash_offset_ + - sizeof(check_header), - input_size, buf); - flash_close_ro_window(); - - if (rv != EC_SUCCESS) { - *response = ARCVE_FLASH_WRITE_FAILED; + rv = write_ap_ro_check_data(AP_RO_HASH_LAYOUT_VERSION_1, + AP_RO_HASH_TYPE_FACTORY, + vc_num_of_ranges, + h1_flash_offset_, + (uint32_t *)p_chk, + buf, + input_size); + if (rv != ARCVE_OK) { + *response = rv; return VENDOR_RC_WRITE_FLASH_FAIL; } |