1 /*
2  * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "hardware/flash.h"
8 #include "pico/bootrom.h"
9 #include "pico/unique_id.h"
10 
11 static_assert(PICO_UNIQUE_BOARD_ID_SIZE_BYTES <= FLASH_UNIQUE_ID_SIZE_BYTES, "Board ID size must at least be the size of flash ID");
12 
13 static pico_unique_board_id_t retrieved_id;
14 
_retrieve_unique_id_on_boot(void)15 static void __attribute__((constructor)) _retrieve_unique_id_on_boot(void) {
16 #if PICO_RP2040
17     #if PICO_NO_FLASH
18         // The hardware_flash call will panic() if called directly on a NO_FLASH
19         // build. Since this constructor is pre-main it would be annoying to
20         // debug, so just produce something well-defined and obviously wrong.
21         for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++)
22             retrieved_id.id[i] = 0xee;
23     #elif (PICO_UNIQUE_BOARD_ID_SIZE_BYTES == FLASH_UNIQUE_ID_SIZE_BYTES)
24         flash_get_unique_id(retrieved_id.id);
25     #elif (PICO_UNIQUE_BOARD_ID_SIZE_BYTES < FLASH_UNIQUE_ID_SIZE_BYTES)
26         // The flash ID is >8 bytes (e.g. IS25LP016D) but we want to keep the
27         // pico unique board ID as 8 bytes, just use the last 8 bytes which are likely to change
28         uint8_t flash_id[FLASH_UNIQUE_ID_SIZE_BYTES];
29         flash_get_unique_id(flash_id);
30         memcpy(retrieved_id.id, flash_id + FLASH_UNIQUE_ID_SIZE_BYTES - PICO_UNIQUE_BOARD_ID_SIZE_BYTES, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
31     #else
32         #error unique board ID size is greater than flash unique ID size
33     #endif
34 #else
35     rom_get_sys_info_fn func = (rom_get_sys_info_fn) rom_func_lookup(ROM_FUNC_GET_SYS_INFO);
36     union {
37         uint32_t words[9];
38         uint8_t bytes[9 * 4];
39     } out;
40     __unused int rc = func(out.words, 9, SYS_INFO_CHIP_INFO);
41     assert(rc == 4);
42     for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
43         retrieved_id.id[i] = out.bytes[PICO_UNIQUE_BOARD_ID_SIZE_BYTES - 1 + 2 * 4 - i];
44     }
45 #endif
46 }
47 
pico_get_unique_board_id(pico_unique_board_id_t * id_out)48 void pico_get_unique_board_id(pico_unique_board_id_t *id_out) {
49     *id_out = retrieved_id;
50 }
51 
pico_get_unique_board_id_string(char * id_out,uint len)52 void pico_get_unique_board_id_string(char *id_out, uint len) {
53     assert(len > 0);
54     size_t i;
55     // Generate hex one nibble at a time
56     for (i = 0; (i < len - 1) && (i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2); i++) {
57         int nibble = (retrieved_id.id[i/2] >> (4 - 4 * (i&1))) & 0xf;
58         id_out[i] = (char)(nibble < 10 ? nibble + '0' : nibble + 'A' - 10);
59     }
60     id_out[i] = 0;
61 }
62