CC312: Allow OTP reads to be more flexible
Allow partial reads of OTP items. Also, fix a minor bug with reading and
writing larger OTP items.
Change-Id: I3e037dbff1e59e9c0b0df347b350de0fffdb2a57
Signed-off-by: Raef Coles <raef.coles@arm.com>
diff --git a/platform/ext/accelerator/cc312/otp_cc312.c b/platform/ext/accelerator/cc312/otp_cc312.c
index e82616a..27ee2b4 100644
--- a/platform/ext/accelerator/cc312/otp_cc312.c
+++ b/platform/ext/accelerator/cc312/otp_cc312.c
@@ -240,18 +240,15 @@
-static enum tfm_plat_err_t otp_read(const uint8_t *addr, size_t size,
+static enum tfm_plat_err_t otp_read(const uint8_t *addr, size_t item_size,
size_t out_len, uint8_t *out)
{
uint32_t* word_ptr;
uint32_t word;
uint32_t start_offset;
- uint8_t out_done;
+ size_t out_done;
size_t copy_size;
-
- if (out_len < size) {
- return TFM_PLAT_ERR_INVALID_INPUT;
- }
+ size_t total_copy_size = item_size < out_len ? item_size : out_len;
/* CC312 OTP can only be read / written in 32 bit words. In order to allow
* access to unaligned uint8_t pointers (as per the function definition):
@@ -267,15 +264,15 @@
* the last word. This is checked for all words, in case the first word is
* also the last word.
*/
- for(out_done = 0; out_done < size;) {
+ for(out_done = 0; out_done < total_copy_size;) {
start_offset = ((uint32_t)addr + out_done) & 0x3;
word_ptr = (uint32_t*)(addr + out_done - start_offset);
word = *word_ptr;
copy_size = sizeof(word) - start_offset;
- if (out_done + copy_size > size) {
- copy_size = size - out_done;
+ if (out_done + copy_size > total_copy_size) {
+ copy_size = total_copy_size - out_done;
}
@@ -322,7 +319,7 @@
uint32_t current_word;
uint32_t word;
uint32_t start_offset;
- uint8_t in_done = 0;
+ size_t in_done = 0;
size_t copy_size;
uint16_t zero_count;
@@ -602,6 +599,7 @@
case PLAT_OTP_ID_HUK:
return otp_read(otp->huk, sizeof(otp->huk), out_len, out);
case PLAT_OTP_ID_IAK:
+ /* The IAK is stored in the rot_public_key slot */
return otp_read(otp->rot_public_key,
sizeof(otp->rot_public_key), out_len, out);
@@ -790,6 +788,7 @@
return otp_write(otp->huk, sizeof(otp->huk), in_len, in,
(uint8_t*)&otp->icv_programmed_flags.huk_zero_bits);
case PLAT_OTP_ID_IAK:
+ /* The IAK is stored in the rot_public_key slot */
return otp_write(otp->rot_public_key, sizeof(otp->rot_public_key),
in_len, in,
(uint8_t*)&otp->oem_programmed_flags.oem_rot_public_key_zero_bits);
@@ -880,6 +879,7 @@
*size = sizeof(otp->huk);
break;
case PLAT_OTP_ID_IAK:
+ /* The IAK is stored in the rot_public_key slot */
*size = sizeof(otp->rot_public_key);
break;
diff --git a/platform/ext/common/template/otp_flash.c b/platform/ext/common/template/otp_flash.c
index 56ffce7..df630f4 100644
--- a/platform/ext/common/template/otp_flash.c
+++ b/platform/ext/common/template/otp_flash.c
@@ -125,14 +125,16 @@
return err;
}
- copy_size = in_len < value_size ? in_len : value_size;
+ if (in_len > value_size) {
+ return TFM_PLAT_ERR_INVALID_INPUT;
+ }
- err = read_otp_nv_counters_flash(offset, buffer, copy_size);
+ err = read_otp_nv_counters_flash(offset, buffer, in_len);
if (err != TFM_PLAT_ERR_SUCCESS) {
return err;
}
- for (idx = 0; idx < copy_size; idx++) {
+ for (idx = 0; idx < in_len; idx++) {
if ((buffer[idx] | in[idx]) != in[idx]) {
return TFM_PLAT_ERR_INVALID_INPUT;
}
@@ -140,7 +142,7 @@
buffer[idx] |= in[idx];
}
- err = write_otp_nv_counters_flash(offset, buffer, copy_size);
+ err = write_otp_nv_counters_flash(offset, buffer, in_len);
if (err != TFM_PLAT_ERR_SUCCESS) {
return err;
}