FRET-qemu/tests/qtest/xlnx-versal-trng-test.c
Romain Malmain 7c3c7877d8 Update to QEMU 9.0.0 (#67)
* Update to QEMU v9.0.0

---------

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Zheyu Ma <zheyuma97@gmail.com>
Signed-off-by: Ido Plat <ido.plat@ibm.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Signed-off-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Signed-off-by: Gregory Price <gregory.price@memverge.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Lorenz Brun <lorenz@brun.one>
Signed-off-by: Yao Xingtao <yaoxt.fnst@fujitsu.com>
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
Signed-off-by: Avihai Horon <avihaih@nvidia.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Joonas Kankaala <joonas.a.kankaala@gmail.com>
Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Glenn Miles <milesg@linux.ibm.com>
Signed-off-by: Oleg Sviridov <oleg.sviridov@red-soft.ru>
Signed-off-by: Artem Chernyshev <artem.chernyshev@red-soft.ru>
Signed-off-by: Yajun Wu <yajunw@nvidia.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Pierre-Clément Tosi <ptosi@google.com>
Signed-off-by: Lei Wang <lei4.wang@intel.com>
Signed-off-by: Wei Wang <wei.w.wang@intel.com>
Signed-off-by: Martin Hundebøll <martin@geanix.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Signed-off-by: Wafer <wafer@jaguarmicro.com>
Signed-off-by: Yuxue Liu <yuxue.liu@jaguarmicro.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com>
Signed-off-by: Zack Buhman <zack@buhman.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Yuquan Wang wangyuquan1236@phytium.com.cn
Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Signed-off-by: Cindy Lu <lulu@redhat.com>
Co-authored-by: Peter Maydell <peter.maydell@linaro.org>
Co-authored-by: Fabiano Rosas <farosas@suse.de>
Co-authored-by: Peter Xu <peterx@redhat.com>
Co-authored-by: Thomas Huth <thuth@redhat.com>
Co-authored-by: Cédric Le Goater <clg@redhat.com>
Co-authored-by: Zheyu Ma <zheyuma97@gmail.com>
Co-authored-by: Ido Plat <ido.plat@ibm.com>
Co-authored-by: Ilya Leoshkevich <iii@linux.ibm.com>
Co-authored-by: Markus Armbruster <armbru@redhat.com>
Co-authored-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Co-authored-by: Paolo Bonzini <pbonzini@redhat.com>
Co-authored-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Co-authored-by: David Hildenbrand <david@redhat.com>
Co-authored-by: Kevin Wolf <kwolf@redhat.com>
Co-authored-by: Stefan Reiter <s.reiter@proxmox.com>
Co-authored-by: Fiona Ebner <f.ebner@proxmox.com>
Co-authored-by: Gregory Price <gregory.price@memverge.com>
Co-authored-by: Lorenz Brun <lorenz@brun.one>
Co-authored-by: Yao Xingtao <yaoxt.fnst@fujitsu.com>
Co-authored-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Co-authored-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Co-authored-by: BALATON Zoltan <balaton@eik.bme.hu>
Co-authored-by: Igor Mammedov <imammedo@redhat.com>
Co-authored-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Co-authored-by: Richard Henderson <richard.henderson@linaro.org>
Co-authored-by: Sven Schnelle <svens@stackframe.org>
Co-authored-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Co-authored-by: Helge Deller <deller@kernel.org>
Co-authored-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
Co-authored-by: Benjamin Gray <bgray@linux.ibm.com>
Co-authored-by: Nicholas Piggin <npiggin@gmail.com>
Co-authored-by: Avihai Horon <avihaih@nvidia.com>
Co-authored-by: Michael Tokarev <mjt@tls.msk.ru>
Co-authored-by: Joonas Kankaala <joonas.a.kankaala@gmail.com>
Co-authored-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
Co-authored-by: Stefan Weil <sw@weilnetz.de>
Co-authored-by: Dayu Liu <liu.dayu@zte.com.cn>
Co-authored-by: Zhao Liu <zhao1.liu@intel.com>
Co-authored-by: Glenn Miles <milesg@linux.vnet.ibm.com>
Co-authored-by: Artem Chernyshev <artem.chernyshev@red-soft.ru>
Co-authored-by: Yajun Wu <yajunw@nvidia.com>
Co-authored-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Co-authored-by: Pierre-Clément Tosi <ptosi@google.com>
Co-authored-by: Wei Wang <wei.w.wang@intel.com>
Co-authored-by: Martin Hundebøll <martin@geanix.com>
Co-authored-by: Michael S. Tsirkin <mst@redhat.com>
Co-authored-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Co-authored-by: Wafer <wafer@jaguarmicro.com>
Co-authored-by: lyx634449800 <yuxue.liu@jaguarmicro.com>
Co-authored-by: Gerd Hoffmann <kraxel@redhat.com>
Co-authored-by: Nguyen Dinh Phi <phind.uet@gmail.com>
Co-authored-by: Zack Buhman <zack@buhman.org>
Co-authored-by: Keith Packard <keithp@keithp.com>
Co-authored-by: Yuquan Wang <wangyuquan1236@phytium.com.cn>
Co-authored-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com>
Co-authored-by: Cindy Lu <lulu@redhat.com>
2024-05-01 16:10:20 +02:00

489 lines
12 KiB
C

/*
* QTests for the Xilinx Versal True Random Number Generator device
*
* Copyright (c) 2023 Advanced Micro Devices, Inc.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "libqtest-single.h"
/* Base Address */
#define TRNG_BASEADDR (0xf1230000)
/* TRNG_INT_CTRL */
#define R_TRNG_INT_CTRL (0x0000)
#define TRNG_INT_CTRL_CERTF_RST_MASK (1 << 5)
#define TRNG_INT_CTRL_DTF_RST_MASK (1 << 4)
#define TRNG_INT_CTRL_DONE_RST_MASK (1 << 3)
#define TRNG_INT_CTRL_CERTF_EN_MASK (1 << 2)
#define TRNG_INT_CTRL_DTF_EN_MASK (1 << 1)
#define TRNG_INT_CTRL_DONE_EN_MASK (1)
/* TRNG_STATUS */
#define R_TRNG_STATUS (0x0004)
#define TRNG_STATUS_QCNT_SHIFT (9)
#define TRNG_STATUS_QCNT_MASK (7 << TRNG_STATUS_QCNT_SHIFT)
#define TRNG_STATUS_CERTF_MASK (1 << 3)
#define TRNG_STATUS_DTF_MASK (1 << 1)
#define TRNG_STATUS_DONE_MASK (1)
/* TRNG_CTRL */
#define R_TRNG_CTRL (0x0008)
#define TRNG_CTRL_PERSODISABLE_MASK (1 << 10)
#define TRNG_CTRL_SINGLEGENMODE_MASK (1 << 9)
#define TRNG_CTRL_PRNGMODE_MASK (1 << 7)
#define TRNG_CTRL_TSTMODE_MASK (1 << 6)
#define TRNG_CTRL_PRNGSTART_MASK (1 << 5)
#define TRNG_CTRL_PRNGXS_MASK (1 << 3)
#define TRNG_CTRL_TRSSEN_MASK (1 << 2)
#define TRNG_CTRL_QERTUEN_MASK (1 << 1)
#define TRNG_CTRL_PRNGSRST_MASK (1)
/* TRNG_EXT_SEED_0 ... _11 */
#define R_TRNG_EXT_SEED_0 (0x0040)
#define R_TRNG_EXT_SEED_11 (R_TRNG_EXT_SEED_0 + 4 * 11)
/* TRNG_PER_STRNG_0 ... 11 */
#define R_TRNG_PER_STRNG_0 (0x0080)
#define R_TRNG_PER_STRNG_11 (R_TRNG_PER_STRNG_0 + 4 * 11)
/* TRNG_CORE_OUTPUT */
#define R_TRNG_CORE_OUTPUT (0x00c0)
/* TRNG_RESET */
#define R_TRNG_RESET (0x00d0)
#define TRNG_RESET_VAL_MASK (1)
/* TRNG_OSC_EN */
#define R_TRNG_OSC_EN (0x00d4)
#define TRNG_OSC_EN_VAL_MASK (1)
/* TRNG_TRNG_ISR, _IMR, _IER, _IDR */
#define R_TRNG_ISR (0x00e0)
#define R_TRNG_IMR (0x00e4)
#define R_TRNG_IER (0x00e8)
#define R_TRNG_IDR (0x00ec)
#define TRNG_IRQ_SLVERR_MASK (1 << 1)
#define TRNG_IRQ_CORE_INT_MASK (1)
/*
* End test with a formatted error message, by embedding the message
* in a GError.
*/
#define TRNG_FAILED(FMT, ...) \
do { \
g_autoptr(GError) err = g_error_new( \
g_quark_from_static_string(trng_qname), 0, \
FMT, ## __VA_ARGS__); \
g_assert_no_error(err); \
} while (0)
static const gchar trng_qname[] = "xlnx-versal-trng-test";
static const uint32_t prng_seed[12] = {
0x01234567, 0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
0x76543210, 0x87654321, 0x98765432, 0xa9876543, 0xba987654, 0xfedcba98,
};
static const uint32_t pers_str[12] = {
0x76543210, 0x87654321, 0x98765432, 0xa9876543, 0xba987654, 0xfedcba98,
0x01234567, 0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
};
static void trng_test_start(void)
{
qtest_start("-machine xlnx-versal-virt");
}
static void trng_test_stop(void)
{
qtest_end();
}
static void trng_test_set_uint_prop(const char *name, uint64_t value)
{
const char *path = "/machine/xlnx-versal/trng";
QDict *response;
response = qmp("{ 'execute': 'qom-set',"
" 'arguments': {"
" 'path': %s,"
" 'property': %s,"
" 'value': %llu"
"} }", path,
name, (unsigned long long)value);
g_assert(qdict_haskey(response, "return"));
qobject_unref(response);
}
static void trng_write(unsigned ra, uint32_t val)
{
writel(TRNG_BASEADDR + ra, val);
}
static uint32_t trng_read(unsigned ra)
{
return readl(TRNG_BASEADDR + ra);
}
static void trng_bit_set(unsigned ra, uint32_t bits)
{
trng_write(ra, (trng_read(ra) | bits));
}
static void trng_bit_clr(unsigned ra, uint32_t bits)
{
trng_write(ra, (trng_read(ra) & ~bits));
}
static void trng_ctrl_set(uint32_t bits)
{
trng_bit_set(R_TRNG_CTRL, bits);
}
static void trng_ctrl_clr(uint32_t bits)
{
trng_bit_clr(R_TRNG_CTRL, bits);
}
static uint32_t trng_status(void)
{
return trng_read(R_TRNG_STATUS);
}
static unsigned trng_qcnt(void)
{
uint32_t sta = trng_status();
return (sta & TRNG_STATUS_QCNT_MASK) >> TRNG_STATUS_QCNT_SHIFT;
}
static const char *trng_info(void)
{
uint32_t sta = trng_status();
uint32_t ctl = trng_read(R_TRNG_CTRL);
static char info[64];
snprintf(info, sizeof(info), "; status=0x%x, ctrl=0x%x", sta, ctl);
return info;
}
static void trng_check_status(uint32_t status_mask, const char *act)
{
uint32_t clear_mask = 0;
uint32_t status;
/*
* Only selected bits are events in R_TRNG_STATUS, and
* clear them needs to go through R_INT_CTRL.
*/
if (status_mask & TRNG_STATUS_CERTF_MASK) {
clear_mask |= TRNG_INT_CTRL_CERTF_RST_MASK;
}
if (status_mask & TRNG_STATUS_DTF_MASK) {
clear_mask |= TRNG_INT_CTRL_DTF_RST_MASK;
}
if (status_mask & TRNG_STATUS_DONE_MASK) {
clear_mask |= TRNG_INT_CTRL_DONE_RST_MASK;
}
status = trng_status();
if ((status & status_mask) != status_mask) {
TRNG_FAILED("%s: Status bitmask 0x%x failed to be 1%s",
act, status_mask, trng_info());
}
/* Remove event */
trng_bit_set(R_TRNG_INT_CTRL, clear_mask);
if (!!(trng_read(R_TRNG_STATUS) & status_mask)) {
TRNG_FAILED("%s: Event 0x%0x stuck at 1 after clear: %s",
act, status_mask, trng_info());
}
}
static void trng_check_done_status(const char *act)
{
trng_check_status(TRNG_STATUS_DONE_MASK, act);
}
static void trng_check_dtf_status(void)
{
trng_check_status(TRNG_STATUS_DTF_MASK, "DTF injection");
}
static void trng_check_certf_status(void)
{
trng_check_status(TRNG_STATUS_CERTF_MASK, "CERTF injection");
}
static void trng_reset(void)
{
trng_write(R_TRNG_RESET, TRNG_RESET_VAL_MASK);
trng_write(R_TRNG_RESET, 0);
}
static void trng_load(unsigned r0, const uint32_t *b384)
{
static const uint32_t zero[12] = { 0 };
unsigned k;
if (!b384) {
b384 = zero;
}
for (k = 0; k < 12; k++) {
trng_write(r0 + 4 * k, b384[k]);
}
}
static void trng_reseed(const uint32_t *seed)
{
const char *act;
uint32_t ctl;
ctl = TRNG_CTRL_PRNGSTART_MASK |
TRNG_CTRL_PRNGXS_MASK |
TRNG_CTRL_TRSSEN_MASK;
trng_ctrl_clr(ctl | TRNG_CTRL_PRNGMODE_MASK);
if (seed) {
trng_load(R_TRNG_EXT_SEED_0, seed);
act = "Reseed PRNG";
ctl &= ~TRNG_CTRL_TRSSEN_MASK;
} else {
trng_write(R_TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
act = "Reseed TRNG";
ctl &= ~TRNG_CTRL_PRNGXS_MASK;
}
trng_ctrl_set(ctl);
trng_check_done_status(act);
trng_ctrl_clr(TRNG_CTRL_PRNGSTART_MASK);
}
static void trng_generate(bool auto_enb)
{
uint32_t ctl;
ctl = TRNG_CTRL_PRNGSTART_MASK | TRNG_CTRL_SINGLEGENMODE_MASK;
trng_ctrl_clr(ctl);
if (auto_enb) {
ctl &= ~TRNG_CTRL_SINGLEGENMODE_MASK;
}
trng_ctrl_set(ctl | TRNG_CTRL_PRNGMODE_MASK);
trng_check_done_status("Generate");
g_assert(trng_qcnt() != 7);
}
static size_t trng_collect(uint32_t *rnd, size_t cnt)
{
size_t i;
for (i = 0; i < cnt; i++) {
if (trng_qcnt() == 0) {
return i;
}
rnd[i] = trng_read(R_TRNG_CORE_OUTPUT);
}
return i;
}
/* These tests all generate 512 bits of random data with the device */
#define TEST_DATA_WORDS (512 / 32)
static void trng_test_autogen(void)
{
const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n;
trng_reset();
/* PRNG run #1 */
trng_reseed(prng_seed);
trng_generate(true);
n = trng_collect(prng, cnt);
if (n != cnt) {
TRNG_FAILED("PRNG_1 Auto-gen test failed: expected = %u, got = %u",
(unsigned)cnt, (unsigned)n);
}
/* TRNG, should not match PRNG */
trng_reseed(NULL);
trng_generate(true);
n = trng_collect(rng, cnt);
if (n != cnt) {
TRNG_FAILED("TRNG Auto-gen test failed: expected = %u, got = %u",
(unsigned)cnt, (unsigned)n);
}
/* PRNG #2: should matches run #1 */
trng_reseed(prng_seed);
trng_generate(true);
n = trng_collect(rng, cnt);
if (n != cnt) {
TRNG_FAILED("PRNG_2 Auto-gen test failed: expected = %u, got = %u",
(unsigned)cnt, (unsigned)n);
}
if (memcmp(rng, prng, sizeof(rng))) {
TRNG_FAILED("PRNG_2 Auto-gen test failed: does not match PRNG_1");
}
}
static void trng_test_oneshot(void)
{
const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[TEST_DATA_WORDS];
size_t n;
trng_reset();
/* PRNG run #1 */
trng_reseed(prng_seed);
trng_generate(false);
n = trng_collect(rng, cnt);
if (n == cnt) {
TRNG_FAILED("PRNG_1 One-shot gen test failed");
}
/* TRNG, should not match PRNG */
trng_reseed(NULL);
trng_generate(false);
n = trng_collect(rng, cnt);
if (n == cnt) {
TRNG_FAILED("TRNG One-shot test failed");
}
}
static void trng_test_per_str(void)
{
const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n;
trng_reset();
/* #1: disabled */
trng_ctrl_set(TRNG_CTRL_PERSODISABLE_MASK);
trng_reseed(prng_seed);
trng_ctrl_clr(TRNG_CTRL_PERSODISABLE_MASK);
trng_generate(true);
n = trng_collect(prng, cnt);
g_assert_cmpuint(n, ==, cnt);
/* #2: zero string should match personalization disabled */
trng_load(R_TRNG_PER_STRNG_0, NULL);
trng_reseed(prng_seed);
trng_generate(true);
n = trng_collect(rng, cnt);
g_assert_cmpuint(n, ==, cnt);
if (memcmp(rng, prng, sizeof(rng))) {
TRNG_FAILED("Failed: PER_DISABLE != PER_STRNG_ALL_ZERO");
}
/* #3: non-zero string should not match personalization disabled */
trng_load(R_TRNG_PER_STRNG_0, pers_str);
trng_reseed(prng_seed);
trng_generate(true);
n = trng_collect(rng, cnt);
g_assert_cmpuint(n, ==, cnt);
if (!memcmp(rng, prng, sizeof(rng))) {
TRNG_FAILED("Failed: PER_DISABLE == PER_STRNG_NON_ZERO");
}
}
static void trng_test_forced_prng(void)
{
const char *prop = "forced-prng";
const uint64_t seed = 0xdeadbeefbad1bad0ULL;
const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n;
trng_reset();
trng_test_set_uint_prop(prop, seed);
/* TRNG run #1 */
trng_reset();
trng_reseed(NULL);
trng_generate(true);
n = trng_collect(prng, cnt);
g_assert_cmpuint(n, ==, cnt);
/* TRNG run #2 should match run #1 */
trng_reset();
trng_reseed(NULL);
trng_generate(true);
n = trng_collect(rng, cnt);
g_assert_cmpuint(n, ==, cnt);
if (memcmp(rng, prng, sizeof(rng))) {
TRNG_FAILED("Forced-prng test failed: results do not match");
}
}
static void trng_test_fault_events(void)
{
const char *prop = "fips-fault-events";
trng_reset();
/* Fault events only when TRSS is enabled */
trng_write(R_TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
trng_ctrl_set(TRNG_CTRL_TRSSEN_MASK);
trng_test_set_uint_prop(prop, TRNG_STATUS_CERTF_MASK);
trng_check_certf_status();
trng_test_set_uint_prop(prop, TRNG_STATUS_DTF_MASK);
trng_check_dtf_status();
trng_reset();
}
int main(int argc, char **argv)
{
int rc;
g_test_init(&argc, &argv, NULL);
#define TRNG_TEST_ADD(n) \
qtest_add_func("/hw/misc/xlnx-versal-trng/" #n, trng_test_ ## n);
TRNG_TEST_ADD(autogen);
TRNG_TEST_ADD(oneshot);
TRNG_TEST_ADD(per_str);
TRNG_TEST_ADD(forced_prng);
TRNG_TEST_ADD(fault_events);
#undef TRNG_TEST_ADD
trng_test_start();
rc = g_test_run();
trng_test_stop();
return rc;
}