ACK: [SRU][F:linux-bluefield][PATCH 1/1] UBUNTU: SAUCE: pka: Test TRNG block before making it available
Kleber Souza
kleber.souza at canonical.com
Fri Apr 23 08:08:26 UTC 2021
On 22.04.21 19:17, Mahantesh Salimath wrote:
> BugLink: https://bugs.launchpad.net/bugs/1925514
>
> * Tests are required in order assess the condition of TRNG.
> Failure in these tests implies TRNG is not functioning as expected
> and hence cannot be trusted. In case of failure disable the TRNG.
>
> Signed-off-by: Mahantesh Salimath <mahantesh at nvidia.com>
> Reviewed-by: Khalil Blaiech <kblaiech at nvidia.com>
> Signed-off-by: Mahantesh Salimath <mahantesh at nvidia.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza at canonical.com>
Thanks
>
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h
> index 07cbcda..1896612 100644
> --- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_addrs.h
> @@ -107,6 +107,15 @@
> #define TRNG_ALARMSTOP_ADDR 0x12058
> #define TRNG_BLOCKCNT_ADDR 0x120E8
> #define TRNG_OPTIONS_ADDR 0x120F0
> +#define TRNG_TEST_ADDR 0x120E0
> +#define TRNG_RAW_L_ADDR 0x12060
> +#define TRNG_RAW_H_ADDR 0x12068
> +#define TRNG_RUN_CNT_ADDR 0x12080
> +#define TRNG_MONOBITCNT_ADDR 0x120B8
> +#define TRNG_POKER_3_0_ADDR 0x120C0
> +#define TRNG_POKER_7_4 0x120C8
> +#define TRNG_POKER_B_8 0x120D0
> +#define TRNG_POKER_F_C 0x120D8
>
> // Control register address/offset. This is accessed from the ARM using 8
> // byte reads/writes however only the bottom 32 bits are implemented.
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h
> index b590477..a562d39 100644
> --- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_config.h
> @@ -179,8 +179,23 @@
> // TRNG Control Register Value; Set bit 10 to start the EIP-76 a.k.a TRNG
> // engine, gathering entropy from the FROs.
> #define PKA_TRNG_CONTROL_REG_VAL 0x00000400
> +
> +// TRNG Control bit
> +#define PKA_TRNG_CONTROL_TEST_MODE 0x100
> +
> // TRNG Status bits
> #define PKA_TRNG_STATUS_READY 0x1
> #define PKA_TRNG_STATUS_SHUTDOWN_OFLO 0x2
> +#define PKA_TRNG_STATUS_TEST_READY 0x100
> +#define PKA_TRNG_STATUS_MONOBIT_FAIL 0x80
> +#define PKA_TRNG_STATUS_RUN_FAIL 0x10
> +#define PKA_TRNG_STATUS_POKER_FAIL 0x40
> +
> +// TRNG Alarm Counter bits
> +#define PKA_TRNG_ALARMCNT_STALL_RUN_POKER 0x8000
> +
> +// TRNG Test bits
> +#define PKA_TRNG_TEST_KNOWN_NOISE 0x20
> +#define PKA_TRNG_TEST_NOISE 0x2000
>
> #endif // __PKA_CONFIG_H__
> diff --git a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> index 8e4141b..358989f 100644
> --- a/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> +++ b/drivers/platform/mellanox/mlxbf_pka/mlxbf_pka_dev.c
> @@ -31,6 +31,7 @@
> // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> //
>
> +#include <linux/delay.h>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> #include <linux/ioport.h>
> @@ -1099,6 +1100,340 @@ static int pka_dev_config_trng_clk(pka_dev_res_t *aic_csr_ptr)
> return ret;
> }
>
> +static int pka_dev_trng_enable_test(void *csr_reg_ptr, uint64_t csr_reg_base,
> + uint32_t test)
> +{
> + uint64_t csr_reg_val, csr_reg_off;
> +
> + // Set the ‘test_mode’ bit in the TRNG_CONTROL register and the
> + // ‘test_known_noise’ bit in the TRNG_TEST register – this will
> + // immediately set the ‘test_ready’ bit (in the TRNG_STATUS register)
> + // to indicate that data can be written. It will also reset the
> + // ‘monobit test’, ‘run test’ and ‘poker test’ circuits to their
> + // initial states. Note that the TRNG need not be enabled for this
> + // test.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off,
> + csr_reg_val | PKA_TRNG_CONTROL_TEST_MODE);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, test);
> +
> + // Wait until the 'test_ready' bit is set
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR);
> + do
> + {
> + csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + } while((csr_reg_val & PKA_TRNG_STATUS_TEST_READY) == 0);
> +
> + // Check whether the 'monobit test', 'run test' and 'poker test'
> + // are reset.
> + if (csr_reg_val & (PKA_TRNG_STATUS_MONOBIT_FAIL
> + | PKA_TRNG_STATUS_RUN_FAIL
> + | PKA_TRNG_STATUS_POKER_FAIL))
> + {
> + PKA_ERROR(PKA_DEV, "Test bits aren't reset, TRNG_STATUS:0x%llx\n",
> + csr_reg_val);
> + return -EAGAIN;
> + }
> +
> + // Set 'stall_run_poker' bit to allow inspecting the state of the
> + // result counters which would otherwise be reset immediately for
> + // the next 20,000 bits block to test.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMCNT_ADDR);
> + csr_reg_val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off,
> + csr_reg_val | PKA_TRNG_ALARMCNT_STALL_RUN_POKER);
> +
> + return 0;
> +}
> +
> +static int pka_dev_trng_test_circuits(void *csr_reg_ptr, uint64_t csr_reg_base,
> + uint64_t datal, uint64_t datah,
> + int count, uint8_t add_half,
> + uint64_t *monobit_fail_cnt,
> + uint64_t *run_fail_cnt,
> + uint64_t *poker_fail_cnt)
> +{
> + uint64_t status, csr_reg_off;
> + int test_idx, error;
> +
> + if (monobit_fail_cnt == NULL || run_fail_cnt == NULL || poker_fail_cnt == NULL)
> + return -EINVAL;
> +
> + error = 0;
> +
> + for (test_idx = 0; test_idx < count; test_idx++)
> + {
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_RAW_L_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, datal);
> +
> + if (add_half)
> + {
> + if (test_idx < count - 1)
> + {
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_RAW_H_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, datah);
> + }
> + }
> + else
> + {
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_RAW_H_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, datah);
> + }
> +
> + // Wait until the ‘test_ready’ bit in the TRNG_STATUS register
> + // becomes ‘1’ again, signaling readiness for the next 64 bits
> + // of test data. At this point, the previous test data has
> + // been handled so the counter states can be inspected.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR);
> + do
> + {
> + status = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + } while((status & PKA_TRNG_STATUS_TEST_READY) == 0);
> +
> + // Check test status bits.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_INTACK_ADDR);
> + if (status & PKA_TRNG_STATUS_MONOBIT_FAIL)
> + {
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_MONOBIT_FAIL);
> + *monobit_fail_cnt += 1;
> + }
> + else if (status & PKA_TRNG_STATUS_RUN_FAIL)
> + {
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_RUN_FAIL);
> + *run_fail_cnt += 1;
> + }
> + else if (status & PKA_TRNG_STATUS_POKER_FAIL)
> + {
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_STATUS_POKER_FAIL);
> + *poker_fail_cnt += 1;
> + }
> +
> + }
> +
> + error = (*monobit_fail_cnt || *poker_fail_cnt || *run_fail_cnt) ? -EIO : 0;
> +
> + return error;
> +}
> +
> +static void pka_dev_trng_disable_test(void *csr_reg_ptr, uint64_t csr_reg_base)
> +{
> + uint64_t status, val, csr_reg_off;
> +
> + // When done, clear the ‘test_known_noise’ bit in the TRNG_TEST
> + // register (will immediately clear the ‘test_ready’ bit in the
> + // TRNG_STATUS register and reset the ‘monobit test’, ‘run test’
> + // and ‘poker test’ circuits) and clear the ‘test_mode’ bit in
> + // the TRNG_CONTROL register.
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_TEST_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_STATUS_ADDR);
> + status = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + if (status & PKA_TRNG_STATUS_TEST_READY)
> + PKA_PRINT(PKA_DEV, "Warning: Test ready bit is still set\n");
> +
> + if (status & (PKA_TRNG_STATUS_MONOBIT_FAIL
> + | PKA_TRNG_STATUS_RUN_FAIL
> + | PKA_TRNG_STATUS_POKER_FAIL))
> + PKA_PRINT(PKA_DEV,
> + "Warning: Test bits are still set, TRNG_STATUS:0x%llx\n", status);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_CONTROL_ADDR);
> + val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off,
> + (val & ~PKA_TRNG_STATUS_TEST_READY));
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base, TRNG_ALARMCNT_ADDR);
> + val = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off,
> + (val & ~PKA_TRNG_ALARMCNT_STALL_RUN_POKER));
> +
> + return;
> +}
> +
> +static int pka_dev_trng_test_known_answer_basic(void *csr_reg_ptr,
> + uint64_t csr_reg_base)
> +{
> + int ret, cnt_idx, cnt_off;
> + uint64_t monobit_fail_cnt, run_fail_cnt, poker_fail_cnt, monobit_cnt;
> + uint64_t poker_cnt[4], csr_reg_off;
> + uint64_t poker_test_exp_cnt[4] = {
> + 0x20f42bf4, 0xaf415f4, 0xf4f4fff4, 0xfff4f4f4
> + };
> +
> + PKA_DEBUG(PKA_DEV, "Run known-answer test circuits\n");
> +
> + monobit_fail_cnt = 0;
> + run_fail_cnt = 0;
> + poker_fail_cnt = 0;
> +
> + ret = pka_dev_trng_enable_test(csr_reg_ptr, csr_reg_base,
> + PKA_TRNG_TEST_KNOWN_NOISE);
> + if (ret)
> + return ret;
> +
> + ret = pka_dev_trng_test_circuits(csr_reg_ptr, csr_reg_base, 0x11111333,
> + 0x3555779f, 11, 0, &monobit_fail_cnt, &run_fail_cnt,
> + &poker_fail_cnt);
> +
> + ret |= pka_dev_trng_test_circuits(csr_reg_ptr, csr_reg_base, 0x01234567,
> + 0x89abcdef, 302, 1, &monobit_fail_cnt, &run_fail_cnt,
> + &poker_fail_cnt);
> +
> + PKA_DEBUG(PKA_DEV, "monobit_fail_cnt : 0x%llx\n", monobit_fail_cnt);
> + PKA_DEBUG(PKA_DEV, "poker_fail_cnt : 0x%llx\n", poker_fail_cnt);
> + PKA_DEBUG(PKA_DEV, "run_fail_cnt : 0x%llx\n", run_fail_cnt);
> +
> + for (cnt_idx = 0, cnt_off = 0; cnt_idx < 4; cnt_idx++, cnt_off += 8)
> + {
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + (TRNG_POKER_3_0_ADDR + cnt_off));
> + poker_cnt[cnt_idx] = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> + }
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_MONOBITCNT_ADDR);
> + monobit_cnt = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + if (!ret)
> + {
> + if (memcmp(poker_cnt, poker_test_exp_cnt, sizeof(poker_test_exp_cnt)))
> + {
> + PKA_DEBUG(PKA_DEV, "invalid poker counters!\n");
> + ret = -EIO;
> + }
> +
> + if (monobit_cnt != 9978)
> + {
> + PKA_DEBUG(PKA_DEV, "invalid sum of squares!\n");
> + ret = -EIO;
> + }
> + }
> +
> + pka_dev_trng_disable_test(csr_reg_ptr, csr_reg_base);
> +
> + return ret;
> +}
> +
> +static int pka_dev_trng_test_known_answer_poker_fail(void *csr_reg_ptr,
> + uint64_t csr_reg_base)
> +{
> + uint64_t monobit_fail_cnt, run_fail_cnt, poker_fail_cnt;
> + int ret;
> +
> + monobit_fail_cnt = 0;
> + run_fail_cnt = 0;
> + poker_fail_cnt = 0;
> +
> + PKA_DEBUG(PKA_DEV, "Run known-answer test circuits (poker fail)\n");
> +
> + pka_dev_trng_enable_test(csr_reg_ptr, csr_reg_base,
> + PKA_TRNG_TEST_KNOWN_NOISE);
> +
> + // Ignore the return value here as it is expected that poker test should
> + // fail. Check failure counts thereafter to assert only poker test has failed.
> + pka_dev_trng_test_circuits(csr_reg_ptr, csr_reg_base, 0xffffffff,
> + 0xffffffff, 11, 0, &monobit_fail_cnt, &run_fail_cnt, &poker_fail_cnt);
> +
> + PKA_DEBUG(PKA_DEV, "monobit_fail_cnt : 0x%llx\n", monobit_fail_cnt);
> + PKA_DEBUG(PKA_DEV, "poker_fail_cnt : 0x%llx\n", poker_fail_cnt);
> + PKA_DEBUG(PKA_DEV, "run_fail_cnt : 0x%llx\n", run_fail_cnt);
> +
> + if (poker_fail_cnt && !run_fail_cnt && !monobit_fail_cnt)
> + ret = 0;
> + else
> + ret = -EIO;
> +
> + pka_dev_trng_disable_test(csr_reg_ptr, csr_reg_base);
> +
> + return ret;
> +}
> +
> +static int pka_dev_trng_test_unknown_answer(void *csr_reg_ptr,
> + uint64_t csr_reg_base)
> +{
> + uint64_t datal, datah, csr_reg_off;
> + int ret, test_idx;
> +
> + datah = 0;
> + datal = 0;
> + ret = 0;
> +
> + PKA_DEBUG(PKA_DEV, "Run unknown-answer self test\n");
> +
> + // First reset, the RAW registers.
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_RAW_L_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_RAW_H_ADDR);
> + pka_dev_io_write(csr_reg_ptr, csr_reg_off, 0);
> +
> + // There is a small probability for this test to fail,
> + // So run the test 10 times, if it succeeds once then
> + // assume that the test passed.
> + for (test_idx = 0; test_idx < 10; test_idx++)
> + {
> + pka_dev_trng_enable_test(csr_reg_ptr, csr_reg_base, PKA_TRNG_TEST_NOISE);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_RAW_L_ADDR);
> + datal = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + csr_reg_off = pka_dev_get_register_offset(csr_reg_base,
> + TRNG_RAW_H_ADDR);
> + datah = pka_dev_io_read(csr_reg_ptr, csr_reg_off);
> +
> + PKA_DEBUG(PKA_DEV, "datal=0x%llx\n", datal);
> + PKA_DEBUG(PKA_DEV, "datah=0x%llx\n", datah);
> +
> + if (!datah && !datal)
> + {
> + ret = -EIO;
> + }
> + else
> + {
> + ret = 0;
> + break;
> + }
> +
> + pka_dev_trng_disable_test(csr_reg_ptr, csr_reg_base);
> + }
> +
> + return ret;
> +}
> +
> +// Test TRNG
> +static int pka_dev_test_trng(void *csr_reg_ptr, uint64_t csr_reg_base)
> +{
> + int ret;
> +
> + ret = 0;
> +
> + ret = pka_dev_trng_test_known_answer_basic(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> + ret = pka_dev_trng_test_known_answer_poker_fail(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> + ret = pka_dev_trng_test_unknown_answer(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + goto exit;
> +
> +exit:
> + return ret;
> +}
> +
> // Configure the TRNG.
> static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> pka_dev_res_t *trng_csr_ptr)
> @@ -1161,6 +1496,10 @@ static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> pka_dev_get_register_offset(csr_reg_base, TRNG_FROENABLE_ADDR);
> pka_dev_io_write(csr_reg_ptr, csr_reg_off, PKA_TRNG_FROENABLE_REG_VAL);
>
> + ret = pka_dev_test_trng(csr_reg_ptr, csr_reg_base);
> + if (ret)
> + return ret;
> +
> // Start the actual engine by setting the 'enable_trng' bit in the
> // TRNG_CONTROL register (also a nice point to set the interrupt mask
> // bits).
> @@ -1174,6 +1513,8 @@ static int pka_dev_config_trng(pka_dev_res_t *aic_csr_ptr,
> // available interrupt until the indicated number of 128-bit words are
> // available in the buffer RAM.
>
> + mdelay(200);
> +
> return ret;
> }
>
> @@ -1224,7 +1565,7 @@ static int pka_dev_ram_zeroize(pka_dev_res_t *ext_csr_ptr)
> static int pka_dev_init_shim(pka_dev_shim_t *shim)
> {
> const uint32_t *farm_img_ptr;
> - uint32_t farm_img_size;
> + uint32_t farm_img_size, data[4], i;
> uint8_t shim_fw_id;
>
> int ret = 0;
> @@ -1297,7 +1638,19 @@ static int pka_dev_init_shim(pka_dev_shim_t *shim)
>
> // Configure the TRNG
> ret = pka_dev_config_trng(&shim->resources.aic_csr,
> - &shim->resources.trng_csr);
> + &shim->resources.trng_csr);
> +
> + // Pull out data from the content of the TRNG buffer RAM and
> + // start the re-generation of new numbers; read and drop 512
> + // words. The read must be done over the 4 TRNG_OUTPUT_X registers
> + // at a time.
> + i = 0;
> + while (i < 128)
> + {
> + pka_dev_trng_read(shim, data, sizeof(data));
> + i++;
> + }
> +
> if (ret)
> {
> // Keep running without TRNG since it does not hurt, but
>
More information about the kernel-team
mailing list