blob: 633ed053a6ff22e0bbdc6e7b0f45da9e22e74b6e [file] [log] [blame]
/* Copyright lowRISC contributors. */
/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */
/* SPDX-License-Identifier: Apache-2.0 */
/* Test access to randomness from OTBN. */
.equ CSR_FG0, 0x7c0
.equ CSR_FG1, 0x7c1
.equ CSR_RND_PREFETCH, 0x7d8
.equ CSR_RND, 0xfc0
.equ CSR_URND, 0xfc1
.section .text.start
/* Test entry point, no arguments need to be passed in nor results returned. */
.globl main
main:
/* Init all-zero reg. */
bn.xor w31, w31, w31
jal x1, test_rnd
jal x1, test_urnd
jal x0, exit_success
.text
/**
* Tests access to cryptographic-strength randomness.
*
* Test reading from the RND CSR and WSR, as well as prefetching randomness
* through RND_PREFETCH.
*
* This test increases confidence in the functional correctness of the RND
* functionality, but isn't free of false positives or negatives.
*
* - The test considers it a failure if two consecutive values read from RND
* are equal. In rare cases, this could happen and the test should be
* re-executed.
* - The randomness prefetch is an optimization to hide unknown and highly
* variable latency from the EDN. This, plus the fact that OTBN software
* cannot measure its own execution time, makes it impossible to automate
* a test for RND_PREFETCH. The instruction is kept nonetheless to help
* debugging with waveforms.
*/
test_rnd:
/* Initial read. */
csrrs x2, CSR_RND, x0
/* Read again, should block for a while. */
csrrs x3, CSR_RND, x0
/* If two consecutive reads return the same random number that's most likely
a bug. (But it doesn't have to be a bug! Re-run the test if it fails.) */
addi x31, x0, 1
beq x2, x3, exit_fail
/* Request a RND value from the EDN by writing to RND_PREFETCH. */
csrrw x0, CSR_RND_PREFETCH, x0
/* Give the prefetch a while to complete. */
/* An EDN request for a random number can take up to around 5 ms. Do not
expect the following RND read to return immediately. */
loopi 1023, 1
nop
/* Read RND again, should block less. */
csrrs x2, CSR_RND, x0
/* Compare to previous value again to detect RND getting stuck. */
addi x31, x0, 2
beq x3, x2, exit_fail
/* Read the RND WSR. */
bn.wsrr w0, 0x1 /* RND */
/* Write w0 to DMEM. */
la x11, rnd_out
bn.sid x0, 0(x11)
/* Read the RND WSR again. */
bn.wsrr w1, 0x1 /* RND */
jal x1, error_checking
ret
/**
* Tests access to "unlimited" randomness (URND).
*
* The test considers it a failure if two consecutive values read from RND
* are equal. In rare cases, this could happen and the test should be
* re-executed.
*/
test_urnd:
/* Read the URND CSR. */
csrrs x2, CSR_URND, x0
/* Read again. */
csrrs x3, CSR_URND, x0
/* If two consecutive reads return the same random number that's most likely
a bug. (But it doesn't have to be a bug! Re-run the test if it fails.) */
addi x31, x0, 32
beq x2, x3, exit_fail
/* Read the URND WSR. */
bn.wsrr w0, 0x2 /* URND */
/* Write w0 to DMEM. */
la x11, urnd_out
bn.sid x0, 0(x11)
/* Read the URND WSR again. */
bn.wsrr w1, 0x2 /* URND */
jal x1, error_checking
ret
/**
* This subroutine performs the following checks:
*
* `w0 != w1` The two random numbers read shall be different.
* `w0 != 0 ` The random numbers shall not have all bits equal to zero.
* `w0 != ~0` The random numbers shall not have all bits equal to one.
*/
error_checking:
/* Fail the test if the two numbers read from RND are equal. */
bn.cmp w0, w1
csrrs x2, CSR_FG0, x0
andi x2, x2, 8 /* Extract Z (zero) bit.*/
addi x31, x31, 1
bne x2, x0, exit_fail
/* Fail the test if all the bits are zero.*/
bn.cmp w0, w31
csrrs x2, CSR_FG0, x0
andi x2, x2, 8 /* Extract Z (zero) bit.*/
addi x31, x31, 1
bne x2, x0, exit_fail
/* Fail the test if all the bits are one. */
bn.not w2, w31 /*`w2 = ~0`*/
bn.cmp w0, w2
csrrs x2, CSR_FG0, x0
andi x2, x2, 8 /* Extract Z (zero) bit.*/
addi x31, x31, 1
bne x2, x0, exit_fail
ret
/* Terminate the program with a 0 (SUCCESS) return code. */
exit_success:
li x10, 0
la x11, rv
sw x10, 0(x11)
ecall
/* Terminate the program with a 1 (FAIL) return code. */
exit_fail:
li x10, 1
la x11, rv
sw x10, 0(x11)
la x11, fail_idx
sw x31, 0(x11)
ecall
.data
/* Return value. */
.globl rv
.balign 4
rv:
.word 0xFFFFFFFF
/* Test status. */
.globl fail_idx
.balign 4
fail_idx:
.word 0x0
/* One of the values read from RND. */
.globl rnd_out
.balign 32
rnd_out:
.zero 32
/* One of the values read from URND. */
.globl urnd_out
.balign 32
urnd_out:
.zero 32