|
8 | 8 | #include <io.h>
|
9 | 9 | #include <kernel/panic.h>
|
10 | 10 | #include <kernel/mutex.h>
|
| 11 | +#include <kernel/tee_common_otp.h> |
11 | 12 | #include <mm/core_memprot.h>
|
12 | 13 | #include <platform.h>
|
13 | 14 | #include <platform_config.h>
|
14 | 15 | #include <rng_support.h>
|
15 | 16 | #include <string.h>
|
| 17 | +#include <string_ext.h> |
| 18 | +#include <utee_defines.h> |
16 | 19 |
|
17 | 20 | #define FIREWALL_DDR_RGN(i) ((i) * 0x4)
|
18 | 21 | #define FIREWALL_DDR_CON 0xf0
|
|
46 | 49 | #define TRNG_POLL_PERIOD_US 0
|
47 | 50 | #define TRNG_POLL_TIMEOUT_US 1000
|
48 | 51 |
|
| 52 | +#define OTP_S_AUTO_CTRL 0x0004 |
| 53 | +#define OTP_S_AUTO_EN 0x0008 |
| 54 | +#define OTP_S_PROG_DATA 0x0010 |
| 55 | +#define OTP_S_DOUT 0x0020 |
| 56 | +#define OTP_S_INT_ST 0x0084 |
| 57 | + |
| 58 | +#define ADDR_SHIFT 16 |
| 59 | +#define BURST_SHIFT 8 |
| 60 | +#define CMD_READ 0 |
| 61 | +#define CMD_WRITE 2 |
| 62 | +#define EN_ENABLE 1 |
| 63 | +#define EN_DISABLE 0 |
| 64 | + |
| 65 | +#define MAX_INDEX 0x300 |
| 66 | +#define BURST_SIZE 8 |
| 67 | +#define OTP_WORD 1 |
| 68 | + |
| 69 | +#define OTP_S_ERROR_BIT BIT32(4) |
| 70 | +#define OTP_S_WR_DONE_BIT BIT32(3) |
| 71 | +#define OTP_S_VERIFY_BIT BIT32(2) |
| 72 | +#define OTP_S_RD_DONE_BIT BIT32(1) |
| 73 | + |
| 74 | +#define OTP_POLL_PERIOD_US 0 |
| 75 | +#define OTP_POLL_TIMEOUT_US 1000 |
| 76 | + |
| 77 | +#define HW_UNIQUE_KEY_INDEX 0x104 |
| 78 | + |
49 | 79 | register_phys_mem_pgdir(MEM_AREA_IO_SEC, FIREWALL_DDR_BASE, FIREWALL_DDR_SIZE);
|
50 | 80 | register_phys_mem_pgdir(MEM_AREA_IO_SEC, FIREWALL_DSU_BASE, FIREWALL_DSU_SIZE);
|
51 | 81 | register_phys_mem_pgdir(MEM_AREA_IO_SEC, TRNG_S_BASE, TRNG_S_SIZE);
|
| 82 | +register_phys_mem_pgdir(MEM_AREA_IO_SEC, OTP_S_BASE, OTP_S_SIZE); |
52 | 83 |
|
53 | 84 | static struct mutex trng_mutex = MUTEX_INITIALIZER;
|
| 85 | +static struct mutex huk_mutex = MUTEX_INITIALIZER; |
54 | 86 |
|
55 | 87 | int platform_secure_ddr_region(int rgn, paddr_t st, size_t sz)
|
56 | 88 | {
|
@@ -160,3 +192,204 @@ TEE_Result hw_get_random_bytes(void *buf, size_t blen)
|
160 | 192 |
|
161 | 193 | return TEE_SUCCESS;
|
162 | 194 | }
|
| 195 | + |
| 196 | +static TEE_Result tee_otp_read_secure(uint32_t *value, uint32_t index, |
| 197 | + uint32_t count) |
| 198 | +{ |
| 199 | + vaddr_t base = (vaddr_t)phys_to_virt(OTP_S_BASE, MEM_AREA_IO_SEC, |
| 200 | + OTP_S_SIZE); |
| 201 | + uint32_t int_status = 0; |
| 202 | + uint32_t i = 0; |
| 203 | + uint32_t val = 0; |
| 204 | + uint32_t auto_ctrl_val = 0; |
| 205 | + TEE_Result res = TEE_SUCCESS; |
| 206 | + |
| 207 | + if (!base) |
| 208 | + panic("OTP_S base not mapped"); |
| 209 | + |
| 210 | + /* Check for invalid parameters or exceeding hardware burst limit */ |
| 211 | + if (!value || !count || count > BURST_SIZE || |
| 212 | + (index + count > MAX_INDEX)) |
| 213 | + return TEE_ERROR_BAD_PARAMETERS; |
| 214 | + |
| 215 | + /* Setup read: index, count, command = READ */ |
| 216 | + auto_ctrl_val = SHIFT_U32(index, ADDR_SHIFT) | |
| 217 | + SHIFT_U32(count, BURST_SHIFT) | |
| 218 | + CMD_READ; |
| 219 | + |
| 220 | + /* Clear any pending interrupts by reading & writing back INT_ST */ |
| 221 | + io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST)); |
| 222 | + |
| 223 | + /* Set read command */ |
| 224 | + io_write32(base + OTP_S_AUTO_CTRL, auto_ctrl_val); |
| 225 | + |
| 226 | + /* Enable read */ |
| 227 | + io_write32(base + OTP_S_AUTO_EN, EN_ENABLE); |
| 228 | + |
| 229 | + /* Wait for RD_DONE or ERROR bits */ |
| 230 | + res = IO_READ32_POLL_TIMEOUT(base + OTP_S_INT_ST, |
| 231 | + int_status, |
| 232 | + (int_status & OTP_S_RD_DONE_BIT) || |
| 233 | + (int_status & OTP_S_ERROR_BIT), |
| 234 | + OTP_POLL_PERIOD_US, |
| 235 | + OTP_POLL_TIMEOUT_US); |
| 236 | + |
| 237 | + /* Clear the interrupt again */ |
| 238 | + io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST)); |
| 239 | + |
| 240 | + if (int_status & OTP_S_ERROR_BIT) { |
| 241 | + EMSG("OTP_S Error"); |
| 242 | + return TEE_ERROR_GENERIC; |
| 243 | + } |
| 244 | + if (res) { |
| 245 | + EMSG("OTP_S Timeout"); |
| 246 | + return TEE_ERROR_BUSY; |
| 247 | + } |
| 248 | + |
| 249 | + /* Read out the data */ |
| 250 | + for (i = 0; i < count; i++) { |
| 251 | + val = io_read32(base + OTP_S_DOUT + |
| 252 | + (i * sizeof(uint32_t))); |
| 253 | + value[i] = val; |
| 254 | + } |
| 255 | + |
| 256 | + return TEE_SUCCESS; |
| 257 | +} |
| 258 | + |
| 259 | +static TEE_Result tee_otp_write_secure(const uint32_t *value, uint32_t index, |
| 260 | + uint32_t count) |
| 261 | +{ |
| 262 | + vaddr_t base = (vaddr_t)phys_to_virt(OTP_S_BASE, MEM_AREA_IO_SEC, |
| 263 | + OTP_S_SIZE); |
| 264 | + uint32_t int_status = 0; |
| 265 | + uint32_t i = 0; |
| 266 | + |
| 267 | + if (!base) |
| 268 | + panic("OTP_S base not mapped"); |
| 269 | + |
| 270 | + /* Check for invalid parameters or exceeding hardware limits */ |
| 271 | + if (!value || !count || count > BURST_SIZE || |
| 272 | + (index + count > MAX_INDEX)) |
| 273 | + return TEE_ERROR_BAD_PARAMETERS; |
| 274 | + |
| 275 | + /* Program OTP words */ |
| 276 | + for (i = 0; i < count; i++) { |
| 277 | + uint32_t old_val = 0; |
| 278 | + uint32_t new_val = 0; |
| 279 | + uint32_t curr_idx = index + i; |
| 280 | + TEE_Result res = TEE_SUCCESS; |
| 281 | + |
| 282 | + /* Setup write: curr_idx, command = WRITE */ |
| 283 | + uint32_t auto_ctrl_val = SHIFT_U32(curr_idx, ADDR_SHIFT) | |
| 284 | + CMD_WRITE; |
| 285 | + |
| 286 | + /* Read existing OTP word to see which bits can be set */ |
| 287 | + res = tee_otp_read_secure(&old_val, curr_idx, OTP_WORD); |
| 288 | + if (res != TEE_SUCCESS) |
| 289 | + return res; |
| 290 | + |
| 291 | + /* Check if bits in value conflict with old_val */ |
| 292 | + if (~*value & old_val) { |
| 293 | + EMSG("OTP_S Program fail"); |
| 294 | + return TEE_ERROR_GENERIC; |
| 295 | + } |
| 296 | + |
| 297 | + /* Only program bits that are currently 0 (0->1) */ |
| 298 | + new_val = *value & ~old_val; |
| 299 | + value++; |
| 300 | + if (!new_val) |
| 301 | + continue; |
| 302 | + |
| 303 | + /* Clear any pending interrupts */ |
| 304 | + io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST)); |
| 305 | + |
| 306 | + /* Set write command */ |
| 307 | + io_write32(base + OTP_S_AUTO_CTRL, auto_ctrl_val); |
| 308 | + |
| 309 | + /* Write the new bits into PROG_DATA register */ |
| 310 | + io_write32(base + OTP_S_PROG_DATA, new_val); |
| 311 | + |
| 312 | + /* Enable the write */ |
| 313 | + io_write32(base + OTP_S_AUTO_EN, EN_ENABLE); |
| 314 | + |
| 315 | + /* Poll for WR_DONE or verify/error bits */ |
| 316 | + res = IO_READ32_POLL_TIMEOUT(base + OTP_S_INT_ST, |
| 317 | + int_status, |
| 318 | + (int_status & OTP_S_WR_DONE_BIT) || |
| 319 | + (int_status & OTP_S_VERIFY_BIT) || |
| 320 | + (int_status & OTP_S_ERROR_BIT), |
| 321 | + OTP_POLL_PERIOD_US, |
| 322 | + OTP_POLL_TIMEOUT_US); |
| 323 | + |
| 324 | + /* Clear INT status bits */ |
| 325 | + io_write32(base + OTP_S_INT_ST, int_status); |
| 326 | + |
| 327 | + /* Check for VERIFY_FAIL, ERROR or timeout */ |
| 328 | + if (int_status & OTP_S_VERIFY_BIT) { |
| 329 | + EMSG("OTP_S Verification fail"); |
| 330 | + return TEE_ERROR_GENERIC; |
| 331 | + } |
| 332 | + if (int_status & OTP_S_ERROR_BIT) { |
| 333 | + EMSG("OTP_S Error"); |
| 334 | + return TEE_ERROR_GENERIC; |
| 335 | + } |
| 336 | + if (res) { |
| 337 | + EMSG("OTP_S Timeout"); |
| 338 | + return TEE_ERROR_BUSY; |
| 339 | + } |
| 340 | + } |
| 341 | + |
| 342 | + return TEE_SUCCESS; |
| 343 | +} |
| 344 | + |
| 345 | +TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) |
| 346 | +{ |
| 347 | + TEE_Result res = TEE_SUCCESS; |
| 348 | + uint32_t buffer[HW_UNIQUE_KEY_LENGTH / sizeof(uint32_t)] = { }; |
| 349 | + bool key_is_empty = true; |
| 350 | + size_t i = 0; |
| 351 | + |
| 352 | + if (!hwkey) |
| 353 | + return TEE_ERROR_BAD_PARAMETERS; |
| 354 | + |
| 355 | + mutex_lock(&huk_mutex); |
| 356 | + |
| 357 | + /* Read 4 words (16 bytes) from OTP at HW_UNIQUE_KEY_INDEX */ |
| 358 | + res = tee_otp_read_secure(buffer, |
| 359 | + HW_UNIQUE_KEY_INDEX, |
| 360 | + HW_UNIQUE_KEY_LENGTH / sizeof(uint32_t)); |
| 361 | + if (res) |
| 362 | + goto out; |
| 363 | + |
| 364 | + /* Check if the buffer is all zero => HUK not present */ |
| 365 | + for (i = 0; i < ARRAY_SIZE(buffer); i++) { |
| 366 | + if (buffer[i] != 0) |
| 367 | + key_is_empty = false; |
| 368 | + } |
| 369 | + |
| 370 | + if (key_is_empty) { |
| 371 | + /* Generate random 128-bit key from TRNG */ |
| 372 | + res = hw_get_random_bytes(buffer, sizeof(buffer)); |
| 373 | + if (res) |
| 374 | + goto out; |
| 375 | + |
| 376 | + /* Write the new HUK into OTP at HW_UNIQUE_KEY_INDEX */ |
| 377 | + res = tee_otp_write_secure(buffer, |
| 378 | + HW_UNIQUE_KEY_INDEX, |
| 379 | + HW_UNIQUE_KEY_LENGTH / |
| 380 | + sizeof(uint32_t)); |
| 381 | + if (res) |
| 382 | + goto out; |
| 383 | + } |
| 384 | + |
| 385 | + /* Copy HUK into hwkey->data */ |
| 386 | + memcpy(hwkey->data, buffer, HW_UNIQUE_KEY_LENGTH); |
| 387 | + |
| 388 | +out: |
| 389 | + /* Clear buffer memory */ |
| 390 | + memzero_explicit(buffer, sizeof(buffer)); |
| 391 | + |
| 392 | + mutex_unlock(&huk_mutex); |
| 393 | + |
| 394 | + return res; |
| 395 | +} |
0 commit comments