1 /*
2  * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #ifndef __TFM_PLAT_OTP_H__
9 #define __TFM_PLAT_OTP_H__
10 
11 #include <stdint.h>
12 #include <stddef.h>
13 #include "tfm_plat_defs.h"
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 #ifdef PLATFORM_DEFAULT_OTP
20 enum tfm_otp_element_id_t {
21     PLAT_OTP_ID_HUK = 0,
22     PLAT_OTP_ID_GUK,
23     PLAT_OTP_ID_IAK,
24     PLAT_OTP_ID_IAK_LEN,
25     PLAT_OTP_ID_IAK_TYPE,
26     PLAT_OTP_ID_IAK_ID,
27 
28     PLAT_OTP_ID_BOOT_SEED,
29     PLAT_OTP_ID_LCS,
30     PLAT_OTP_ID_IMPLEMENTATION_ID,
31     PLAT_OTP_ID_CERT_REF,
32     PLAT_OTP_ID_VERIFICATION_SERVICE_URL,
33     PLAT_OTP_ID_PROFILE_DEFINITION,
34 
35     PLAT_OTP_ID_BL2_ROTPK_0,
36     PLAT_OTP_ID_BL2_ROTPK_1,
37     PLAT_OTP_ID_BL2_ROTPK_2,
38     PLAT_OTP_ID_BL2_ROTPK_3,
39 
40     PLAT_OTP_ID_NV_COUNTER_BL2_0,
41     PLAT_OTP_ID_NV_COUNTER_BL2_1,
42     PLAT_OTP_ID_NV_COUNTER_BL2_2,
43     PLAT_OTP_ID_NV_COUNTER_BL2_3,
44 
45     PLAT_OTP_ID_NV_COUNTER_NS_0,
46     PLAT_OTP_ID_NV_COUNTER_NS_1,
47     PLAT_OTP_ID_NV_COUNTER_NS_2,
48 
49     PLAT_OTP_ID_KEY_BL2_ENCRYPTION,
50     PLAT_OTP_ID_BL1_2_IMAGE,
51     PLAT_OTP_ID_BL1_2_IMAGE_HASH,
52     PLAT_OTP_ID_BL2_IMAGE_HASH,
53     PLAT_OTP_ID_BL1_ROTPK_0,
54 
55     PLAT_OTP_ID_NV_COUNTER_BL1_0,
56 
57     PLAT_OTP_ID_ENTROPY_SEED,
58 
59     PLAT_OTP_ID_SECURE_DEBUG_PK,
60 
61     PLAT_OTP_ID_MAX = UINT32_MAX,
62 };
63 #else
64 #include "platform_otp_ids.h"
65 #endif /* PLATFORM_DEFAULT_OTP */
66 
67 /* These are separate from the tfm_security_lifecycle_t definitions because here
68  * the possible transitions are encoded by using the property that OTP bits can
69  * be changed from a 0 to a 1, but not from a 1 to a 0.
70  *
71  * For example:
72  * If the device is in PLAT_OTP_LCS_SECURED, it can transition to
73  * PLAT_OTP_LCS_DECOMMISSIONED by setting bit 3, but cannot transition back to
74  * PLAT_OTP_LCS_PSA_ROT_PROVISIONING as that would require setting bit 2 to 0,
75  * which cannot be done as per OTP semantics.
76  *
77  * NON_PSA_ROT_DEBUG and RECOVERABLE_PSA_ROT_DEBUG must be handled separately to
78  * OTP memory as they are reversible transitions from SECURED, and OTP cannot
79  * handle reversible transitions.
80  */
81 enum plat_otp_lcs_t {
82     PLAT_OTP_LCS_ASSEMBLY_AND_TEST    = 0x0,
83     PLAT_OTP_LCS_PSA_ROT_PROVISIONING = 0x1,
84     PLAT_OTP_LCS_SECURED              = 0x3,
85     PLAT_OTP_LCS_DECOMMISSIONED       = 0x7,
86     PLAT_OTP_LCS_UNKNOWN              = 0xF,
87     PLAT_OTP_LCS_MAX                  = UINT32_MAX,
88 };
89 
90 /**
91  * \brief                               Initialises OTP storage.
92  *
93  * \return                              TFM_PLAT_ERR_SUCCESS if the
94  *                                      initialization succeeds, otherwise
95  *                                      TFM_PLAT_ERR_SYSTEM_ERR
96  */
97 enum tfm_plat_err_t tfm_plat_otp_init(void);
98 
99 /**
100  * \brief                               Reads the given OTP element.
101  *
102  * \param[in]  id                       ID of the element to read.
103  * \param[in]  out_len                  Size of the buffer to read the element
104  *                                      into in bytes.
105  * \param[out] out                      Buffer to read the element into.
106  *
107  * \note                                If the size of the internal OTP
108  *                                      representation of the item is different
109  *                                      to out_len, then the smaller of the two
110  *                                      is the amount of bytes that must be
111  *                                      read.
112  *
113  * \retval TFM_PLAT_ERR_SUCCESS         The element is read successfully.
114  * \retval TFM_PLAT_ERR_UNSUPPORTED     The given element has not been
115  *                                      instanciated in OTP memory by this
116  *                                      particular platform.
117  * \retval TFM_PLAT_ERR_SYSTEM_ERR      An unspecified error occurred.
118  */
119 enum tfm_plat_err_t tfm_plat_otp_read(enum tfm_otp_element_id_t id,
120                                       size_t out_len, uint8_t *out);
121 
122 /**
123  * \brief                               Writes the specified bytes to the given
124  *                                      OTP element.
125  *
126  * \param[in]  id                       ID of the element to write.
127  * \param[in]  in_len                   Size of the buffer to write to the
128  *                                      element in bytes.
129  * \param[in]  in                       Pointer to the buffer to write to the
130  *                                      element.
131  *
132  * \note                                This function must implement the OTP
133  *                                      writing semantics, where any bit
134  *                                      currently set to 1 cannot be set to 0.
135  *                                      If such a write is requested, the
136  *                                      function should return an error code and
137  *                                      not alter the contents of OTP memory.
138  *
139  * \note                                If the size of the internal OTP
140  *                                      representation of the item is smaller
141  *                                      than in_len, this function must return
142  *                                      an error other than TFM_PLAT_ERR_SUCCESS
143  *                                      and not write any OTP.
144  *
145  * \retval TFM_PLAT_ERR_SUCCESS         The OTP is written successfully
146  * \retval TFM_PLAT_ERR_UNSUPPORTED     The element is not supported.
147  * \retval TFM_PLAT_ERR_SYSTEM_ERR      An unspecified error occurred.
148  */
149 enum tfm_plat_err_t tfm_plat_otp_write(enum tfm_otp_element_id_t id,
150                                        size_t in_len, const uint8_t *in);
151 
152 /**
153  * \brief                               Returns the size of a given OTP element.
154  *
155  * \param[in]  id                       ID of the element.
156  * \param[out] size                     Size of the element.
157  *
158  * \retval TFM_PLAT_ERR_SUCCESS         The size is returned successfully.
159  * \retval TFM_PLAT_ERR_UNSUPPORTED     The element is not supported.
160  * \retval TFM_PLAT_ERR_SYSTEM_ERR      An unspecified error occurred.
161  */
162 enum tfm_plat_err_t tfm_plat_otp_get_size(enum tfm_otp_element_id_t id,
163                                           size_t *size);
164 
165 #ifdef __cplusplus
166 }
167 #endif
168 
169 #endif /* __TFM_PLAT_OTP_H__ */
170