1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <console/console.h>
4 #include <spi-generic.h>
10 #include "spi_flash_internal.h"
12 void spi_flash_fill_rpmc_caps(struct spi_flash
*flash
)
14 struct sfdp_rpmc_info rpmc_info
;
16 flash
->rpmc_caps
.rpmc_available
= false;
18 if (spi_flash_get_sfdp_rpmc(flash
, &rpmc_info
) != CB_SUCCESS
)
21 if (rpmc_info
.monotonic_counter_size
!= SFDP_RPMC_COUNTER_BITS_32
) {
22 printk(BIOS_WARNING
, "RPMC: unexpected counter size\n");
26 flash
->rpmc_caps
.poll_op2_ext_stat
= rpmc_info
.busy_polling_method
==
27 SFDP_RPMC_POLL_OP2_EXTENDED_STATUS
;
28 flash
->rpmc_caps
.number_of_counters
= rpmc_info
.number_of_counters
;
29 flash
->rpmc_caps
.op1_write_cmd
= rpmc_info
.op1_write_command
;
30 flash
->rpmc_caps
.op2_read_cmd
= rpmc_info
.op2_read_command
;
31 flash
->rpmc_caps
.rpmc_available
= true;
34 static bool spi_flash_rpmc_is_available(const struct spi_flash
*flash
)
36 return flash
->rpmc_caps
.rpmc_available
;
39 #define RPMC_OP2_READ_BUF_EXT_STATUS_OFFSET 0
40 #define RPMC_OP2_READ_BUF_TAG_OFFSET 1
41 #define RPMC_OP2_READ_BUF_COUNTER_DATA_OFFSET (1 + SPI_RPMC_TAG_LEN)
42 #define RPMC_OP2_READ_BUF_SIGNATURE_OFFSET (1 + SPI_RPMC_TAG_LEN + SPI_RPMC_COUNTER_DATA_LEN)
45 * 'extended_status', 'tag', 'counter_data', and 'signature' may be NULL if the caller
46 * doesn't need the value. 'tag' must be a SPI_RPMC_TAG_LEN bytes long buffer, 'signature'
47 * must be a SPI_RPMC_SIG_LEN bytes long buffer. When only 'extended_status' is non-NULL, only
48 * the extended status is read back.
50 static enum cb_err
spi_flash_rpmc_op2_read(const struct spi_flash
*flash
,
51 uint8_t *extended_status
, uint8_t *tag
,
52 uint8_t *counter_data
, uint8_t *signature
)
55 const bool only_check_extended_status
= extended_status
!= NULL
&& tag
== NULL
&&
56 counter_data
== NULL
&& signature
== NULL
;
58 /* command and dummy byte */
59 uint8_t write_buf
[1 + 1];
60 /* extended status, tag, counter data, signature */
61 uint8_t read_buf
[1 + SPI_RPMC_TAG_LEN
+ SPI_RPMC_COUNTER_DATA_LEN
+ SPI_RPMC_SIG_LEN
];
63 write_buf
[0] = flash
->rpmc_caps
.op2_read_cmd
;
64 write_buf
[1] = 0x00; /* dummy byte */
66 cmd_ret
= spi_flash_cmd_multi(&flash
->spi
, write_buf
, sizeof(write_buf
), read_buf
,
67 only_check_extended_status
? 1 : sizeof(read_buf
));
72 if (extended_status
!= NULL
)
73 *extended_status
= read_buf
[RPMC_OP2_READ_BUF_EXT_STATUS_OFFSET
];
76 memcpy(tag
, &read_buf
[RPMC_OP2_READ_BUF_TAG_OFFSET
], SPI_RPMC_TAG_LEN
);
78 if (counter_data
!= NULL
)
79 memcpy(counter_data
, &read_buf
[RPMC_OP2_READ_BUF_COUNTER_DATA_OFFSET
],
80 SPI_RPMC_COUNTER_DATA_LEN
);
82 if (signature
!= NULL
)
83 memcpy(signature
, &read_buf
[RPMC_OP2_READ_BUF_SIGNATURE_OFFSET
],
89 static enum cb_err
spi_flash_rpmc_op2_get_exteded_status(const struct spi_flash
*flash
,
90 uint8_t *extended_status
)
92 return spi_flash_rpmc_op2_read(flash
, extended_status
, NULL
, NULL
, NULL
);
95 #define RPMC_OP2_EXT_STATUS_SUCCESS BIT(7)
96 #define RPMC_OP2_EXT_STATUS_ERR_FATAL BIT(5)
97 #define RPMC_OP2_EXT_STATUS_ERR_BAD_COUNTER BIT(4)
98 #define RPMC_OP2_EXT_STATUS_ERR_UNINITIALIZED BIT(3)
99 #define RPMC_OP2_EXT_STATUS_ERR_INVALID BIT(2)
100 #define RPMC_OP2_EXT_STATUS_ERR_OTHER BIT(1)
101 #define RPMC_OP2_EXT_STATUS_POLL_BUSY BIT(0)
103 static bool spi_flash_rpmc_is_extended_status_successful(uint8_t extended_status
)
105 return extended_status
& RPMC_OP2_EXT_STATUS_SUCCESS
;
108 static void spi_flash_rpmc_print_extended_status_error(uint8_t extended_status
)
110 if (extended_status
& RPMC_OP2_EXT_STATUS_POLL_BUSY
)
111 printk(BIOS_WARNING
, "SPI flash RPMC is busy\n");
113 if (extended_status
& RPMC_OP2_EXT_STATUS_ERR_OTHER
)
114 printk(BIOS_ERR
, "SPI flash RPMC other error\n");
116 if (extended_status
& RPMC_OP2_EXT_STATUS_ERR_INVALID
)
117 printk(BIOS_ERR
, "SPI flash RPMC invalid input\n");
119 if (extended_status
& RPMC_OP2_EXT_STATUS_ERR_UNINITIALIZED
)
120 printk(BIOS_ERR
, "SPI flash RPMC uninitialized\n");
122 if (extended_status
& RPMC_OP2_EXT_STATUS_ERR_BAD_COUNTER
)
123 printk(BIOS_ERR
, "SPI flash RPMC counter mismatch\n");
125 if (extended_status
& RPMC_OP2_EXT_STATUS_ERR_FATAL
)
126 printk(BIOS_ERR
, "SPI flash RPMC fatal error\n");
129 static enum cb_err
spi_flash_rpmc_check_extended_status(const struct spi_flash
*flash
)
131 uint8_t extended_status
;
133 if (spi_flash_rpmc_op2_get_exteded_status(flash
, &extended_status
) != CB_SUCCESS
)
136 if (spi_flash_rpmc_is_extended_status_successful(extended_status
))
139 spi_flash_rpmc_print_extended_status_error(extended_status
);
144 static enum cb_err
spi_flash_rpmc_poll_op2(const struct spi_flash
*flash
, uint64_t timeout_ms
)
146 unsigned int attempt
= 0;
147 uint8_t extended_status
;
150 stopwatch_init_msecs_expire(&sw
, timeout_ms
);
154 if (spi_flash_rpmc_op2_get_exteded_status(flash
, &extended_status
)) {
156 "SPI command failed on attempt %d\n", attempt
);
160 if ((extended_status
& RPMC_OP2_EXT_STATUS_POLL_BUSY
) == 0)
162 } while (!stopwatch_expired(&sw
));
164 printk(BIOS_WARNING
, "SPI RPMC poll timeout at %lld msec after %d attempts\n",
165 stopwatch_duration_msecs(&sw
), attempt
);
170 static enum cb_err
spi_flash_rpmc_wait_ready(const struct spi_flash
*flash
,
173 if (!flash
->rpmc_caps
.poll_op2_ext_stat
) {
174 /* poll read status */
175 if (spi_flash_cmd_wait_ready(flash
, timeout_ms
))
178 /* poll RPMC OP2 extended status */
179 if (spi_flash_rpmc_poll_op2(flash
, timeout_ms
) != CB_SUCCESS
)
186 static bool spi_flash_rpmc_is_valid_counter_addr(const struct spi_flash
*flash
,
187 uint8_t counter_addr
)
189 return counter_addr
< flash
->rpmc_caps
.number_of_counters
;
192 /* TODO: replace with proper value read from SFDP?! */
193 #define SPI_FLASH_RPMC_TIMEOUT_MS 200
195 #define RPMC_OP1_CMD_WRITE_ROOT_KEY_REGISTER 0x00
196 #define RPMC_OP1_CMD_UPDATE_HMAC_KEY_REGISTER 0x01
197 #define RPMC_OP1_CMD_INCREMENT_MONOTONIC_COUNTER 0x02
198 #define RPMC_OP1_CMD_REQUEST_MONOTONIC_COUNTER 0x03
200 enum cb_err
spi_flash_rpmc_write_root_key(const struct spi_flash
*flash
, uint8_t counter_addr
,
201 const uint8_t *root_key
,
202 const uint8_t *truncated_signature
)
204 /* command, command type, counter address, reserved, root key, truncated signature */
205 uint8_t buf
[1 + 1 + 1 + 1 + SPI_RPMC_ROOT_KEY_LEN
+ SPI_RPMC_TRUNCTAED_SIG_LEN
];
207 if (!spi_flash_rpmc_is_available(flash
))
210 if (!spi_flash_rpmc_is_valid_counter_addr(flash
, counter_addr
))
213 buf
[0] = flash
->rpmc_caps
.op1_write_cmd
;
214 buf
[1] = RPMC_OP1_CMD_WRITE_ROOT_KEY_REGISTER
;
215 buf
[2] = counter_addr
;
216 buf
[3] = 0x00; /* reserved */
217 memcpy(&buf
[4], root_key
, SPI_RPMC_ROOT_KEY_LEN
);
218 memcpy(&buf
[4 + SPI_RPMC_ROOT_KEY_LEN
], truncated_signature
,
219 SPI_RPMC_TRUNCTAED_SIG_LEN
);
221 if (spi_flash_cmd_multi(&flash
->spi
, buf
, sizeof(buf
), NULL
, 0))
224 if (spi_flash_rpmc_wait_ready(flash
, SPI_FLASH_RPMC_TIMEOUT_MS
) != CB_SUCCESS
)
227 if (spi_flash_rpmc_check_extended_status(flash
) != CB_SUCCESS
)
233 enum cb_err
spi_flash_rpmc_update_hmac_key(const struct spi_flash
*flash
, uint8_t counter_addr
,
234 uint8_t *key_data
, const uint8_t *signature
)
236 /* command, command type, counter address, reserved, key data, signature */
237 uint8_t buf
[1 + 1 + 1 + 1 + SPI_RPMC_KEY_DATA_LEN
+ SPI_RPMC_SIG_LEN
];
239 if (!spi_flash_rpmc_is_available(flash
))
242 if (!spi_flash_rpmc_is_valid_counter_addr(flash
, counter_addr
))
245 buf
[0] = flash
->rpmc_caps
.op1_write_cmd
;
246 buf
[1] = RPMC_OP1_CMD_UPDATE_HMAC_KEY_REGISTER
;
247 buf
[2] = counter_addr
;
248 buf
[3] = 0x00; /* reserved */
249 memcpy(&buf
[4], key_data
, SPI_RPMC_KEY_DATA_LEN
);
250 memcpy(&buf
[4 + SPI_RPMC_KEY_DATA_LEN
], signature
, SPI_RPMC_SIG_LEN
);
252 if (spi_flash_cmd_multi(&flash
->spi
, buf
, sizeof(buf
), NULL
, 0))
255 if (spi_flash_rpmc_wait_ready(flash
, SPI_FLASH_RPMC_TIMEOUT_MS
) != CB_SUCCESS
)
258 if (spi_flash_rpmc_check_extended_status(flash
) != CB_SUCCESS
)
264 enum cb_err
spi_flash_rpmc_increment(const struct spi_flash
*flash
, uint8_t counter_addr
,
265 const uint8_t *counter_data
, const uint8_t *signature
)
267 /* command, command type, counter address, reserved, counter data, signature */
268 uint8_t buf
[1 + 1 + 1 + 1 + SPI_RPMC_COUNTER_DATA_LEN
+ SPI_RPMC_SIG_LEN
];
270 if (!spi_flash_rpmc_is_available(flash
))
273 if (!spi_flash_rpmc_is_valid_counter_addr(flash
, counter_addr
))
276 buf
[0] = flash
->rpmc_caps
.op1_write_cmd
;
277 buf
[1] = RPMC_OP1_CMD_INCREMENT_MONOTONIC_COUNTER
;
278 buf
[2] = counter_addr
;
279 buf
[3] = 0x00; /* reserved */
280 memcpy(&buf
[4], counter_data
, SPI_RPMC_COUNTER_DATA_LEN
);
281 memcpy(&buf
[4 + SPI_RPMC_COUNTER_DATA_LEN
], signature
, SPI_RPMC_SIG_LEN
);
283 if (spi_flash_cmd_multi(&flash
->spi
, buf
, sizeof(buf
), NULL
, 0))
286 if (spi_flash_rpmc_wait_ready(flash
, SPI_FLASH_RPMC_TIMEOUT_MS
) != CB_SUCCESS
)
289 if (spi_flash_rpmc_check_extended_status(flash
) != CB_SUCCESS
)
295 enum cb_err
spi_flash_rpmc_request(const struct spi_flash
*flash
, uint8_t counter_addr
,
296 const uint8_t *tag
, const uint8_t *signature
,
297 uint8_t *counter_data
, uint8_t *signature_out
)
299 /* command, command type, counter address, reserved, tag, signature */
300 uint8_t buf
[1 + 1 + 1 + 1 + SPI_RPMC_TAG_LEN
+ SPI_RPMC_SIG_LEN
];
301 uint8_t extended_status
;
303 if (!spi_flash_rpmc_is_available(flash
))
306 if (!spi_flash_rpmc_is_valid_counter_addr(flash
, counter_addr
))
309 buf
[0] = flash
->rpmc_caps
.op1_write_cmd
;
310 buf
[1] = RPMC_OP1_CMD_REQUEST_MONOTONIC_COUNTER
;
311 buf
[2] = counter_addr
;
312 buf
[3] = 0x00; /* reserved */
313 memcpy(&buf
[4], tag
, SPI_RPMC_TAG_LEN
);
314 memcpy(&buf
[4 + SPI_RPMC_TAG_LEN
], signature
, SPI_RPMC_SIG_LEN
);
316 if (spi_flash_cmd_multi(&flash
->spi
, buf
, sizeof(buf
), NULL
, 0))
319 if (spi_flash_rpmc_wait_ready(flash
, SPI_FLASH_RPMC_TIMEOUT_MS
) != CB_SUCCESS
)
323 * Since we need to read back more than just the extended status for this command and
324 * want to avoid unnecessary SPI transactions, spi_flash_rpmc_check_extended_status
327 if (spi_flash_rpmc_op2_read(flash
, &extended_status
, NULL
, counter_data
, signature_out
)
331 if (!spi_flash_rpmc_is_extended_status_successful(extended_status
)) {
332 spi_flash_rpmc_print_extended_status_error(extended_status
);