Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
6080aac9
Commit
6080aac9
authored
Feb 05, 2021
by
André Przywara
Committed by
TrustedFirmware Code Review
Feb 05, 2021
Browse files
Merge "Add TRNG Firmware Interface service" into integration
parents
d5105d99
7dfb9911
Changes
13
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
6080aac9
#
# Copyright (c) 2013-202
0
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2013-202
1
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -1018,6 +1018,7 @@ $(eval $(call add_defines,\
SPM_MM
\
SPMD_SPM_AT_SEL2
\
TRUSTED_BOARD_BOOT
\
TRNG_SUPPORT
\
USE_COHERENT_MEM
\
USE_DEBUGFS
\
ARM_IO_IN_DTB
\
...
...
bl31/bl31.mk
View file @
6080aac9
#
# Copyright (c) 2013-202
0
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2013-202
1
, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -68,6 +68,11 @@ BL31_SOURCES += services/std_svc/sdei/sdei_dispatch.S \
services/std_svc/sdei/sdei_state.c
endif
ifeq
(${TRNG_SUPPORT},1)
BL31_SOURCES
+=
services/std_svc/trng/trng_main.c
\
services/std_svc/trng/trng_entropy_pool.c
endif
ifeq
(${ENABLE_SPE_FOR_LOWER_ELS},1)
BL31_SOURCES
+=
lib/extensions/spe/spe.c
endif
...
...
docs/getting_started/porting-guide.rst
View file @
6080aac9
...
...
@@ -2009,6 +2009,53 @@ interrupt and the interrupt ID are passed as parameters.
The default implementation only prints out a warning message.
.. _porting_guide_trng_requirements:
TRNG porting requirements
~~~~~~~~~~~~~~~~~~~~~~~~~
The |TRNG| backend requires the platform to provide the following values
and mandatory functions.
Values
......
value: uuid_t plat_trng_uuid [mandatory]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This value must be defined to the UUID of the TRNG backend that is specific to
the hardware after ``plat_trng_setup`` function is called. This value must
conform to the SMCCC calling convention; The most significant 32 bits of the
UUID must not equal ``0xffffffff`` or the signed integer ``-1`` as this value in
w0 indicates failure to get a TRNG source.
Functions
.........
Function: void plat_entropy_setup(void) [mandatory]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
Argument: none
Return: none
This function is expected to do platform-specific initialization of any TRNG
hardware. This may include generating a UUID from a hardware-specific seed.
Function: bool plat_get_entropy(uint64_t \*out) [mandatory]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
Argument: uint64_t *
Return: bool
Out : when the return value is true, the entropy has been written into the
storage pointed to
This function writes entropy into storage provided by the caller. If no entropy
is available, it must return false and the storage must not be written.
Power State Coordination Interface (in BL31)
--------------------------------------------
...
...
@@ -2941,7 +2988,7 @@ amount of open resources per driver.
--------------
*Copyright (c) 2013-202
0
, Arm Limited and Contributors. All rights reserved.*
*Copyright (c) 2013-202
1
, Arm Limited and Contributors. All rights reserved.*
.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
.. _Arm Generic Interrupt Controller version 2.0 (GICv2): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0048b/index.html
...
...
docs/global_substitutions.txt
View file @
6080aac9
...
...
@@ -56,6 +56,7 @@
.. |TF-M| replace:: :term:`TF-M`
.. |TLB| replace:: :term:`TLB`
.. |TLK| replace:: :term:`TLK`
.. |TRNG| replace:: :term:`TRNG`
.. |TSP| replace:: :term:`TSP`
.. |TZC| replace:: :term:`TZC`
.. |UBSAN| replace:: :term:`UBSAN`
...
...
docs/glossary.rst
View file @
6080aac9
...
...
@@ -193,6 +193,9 @@ You can find additional definitions in the `Arm Glossary`_.
TLK
Trusted Little Kernel. A Trusted OS from NVIDIA.
TRNG
True Randon Number Generator (hardware based)
TSP
Test Secure Payload
...
...
include/plat/common/plat_trng.h
0 → 100644
View file @
6080aac9
/*
* Copyright (c) 2021, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLAT_TRNG_H
#define PLAT_TRNG_H
#include <tools_share/uuid.h>
/* TRNG platform functions */
extern
uuid_t
plat_trng_uuid
;
void
plat_entropy_setup
(
void
);
bool
plat_get_entropy
(
uint64_t
*
out
);
#endif
/* PLAT_TRNG_H */
include/plat/common/platform.h
View file @
6080aac9
/*
* Copyright (c) 2013-202
0
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-202
1
, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -13,6 +13,9 @@
#if defined(SPD_spmd)
#include <services/spm_core_manifest.h>
#endif
#if TRNG_SUPPORT
#include "plat_trng.h"
#endif
/*******************************************************************************
* Forward declarations
...
...
include/services/trng_svc.h
0 → 100644
View file @
6080aac9
/*
* Copyright (c) 2021, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TRNG_SVC_H
#define TRNG_SVC_H
#include <stdbool.h>
#include <stdint.h>
#include <lib/smccc.h>
/* SMC function IDs for TRNG queries */
#define ARM_TRNG_VERSION U(0x84000050)
#define ARM_TRNG_FEATURES U(0x84000051)
#define ARM_TRNG_GET_UUID U(0x84000052)
#define ARM_TRNG_RND32 U(0x84000053)
#define ARM_TRNG_RND64 U(0xc4000053)
/* TRNG version numbers */
#define TRNG_VERSION_MAJOR (0x1)
#define TRNG_VERSION_MINOR (0x0)
/* TRNG Error Numbers */
#define TRNG_E_SUCCESS (0)
#define TRNG_E_NOT_SUPPORTED (-1)
#define TRNG_E_INVALID_PARAMS (-2)
#define TRNG_E_NO_ENTROPY (-3)
#define TRNG_E_NOT_IMPLEMENTED (-4)
#if TRNG_SUPPORT
void
trng_setup
(
void
);
bool
is_trng_fid
(
uint32_t
smc_fid
);
#else
static
inline
void
trng_setup
(
void
)
{
}
static
inline
bool
is_trng_fid
(
uint32_t
smc_fid
)
{
return
false
;
}
#endif
uintptr_t
trng_smc_handler
(
uint32_t
smc_fid
,
u_register_t
x1
,
u_register_t
x2
,
u_register_t
x3
,
u_register_t
x4
,
void
*
cookie
,
void
*
handle
,
u_register_t
flags
);
#endif
/* TRNG_SVC_H */
make_helpers/defaults.mk
View file @
6080aac9
#
# Copyright (c) 2016-202
0
, ARM Limited. All rights reserved.
# Copyright (c) 2016-202
1
, ARM Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
...
...
@@ -209,6 +209,9 @@ SAVE_KEYS := 0
# Software Delegated Exception support
SDEI_SUPPORT
:=
0
# True Random Number firmware Interface
TRNG_SUPPORT
:=
0
# Whether code and read-only data should be put on separate memory pages. The
# platform Makefile is free to override this value.
SEPARATE_CODE_AND_RODATA
:=
0
...
...
services/std_svc/std_svc_setup.c
View file @
6080aac9
/*
* Copyright (c) 2014-202
0
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-202
1
, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
...
...
@@ -17,6 +17,7 @@
#include <services/spm_mm_svc.h>
#include <services/spmd_svc.h>
#include <services/std_svc.h>
#include <services/trng_svc.h>
#include <smccc_helpers.h>
#include <tools_share/uuid.h>
...
...
@@ -63,6 +64,8 @@ static int32_t std_svc_setup(void)
sdei_init
();
#endif
trng_setup
();
return
ret
;
}
...
...
@@ -139,6 +142,11 @@ static uintptr_t std_svc_smc_handler(uint32_t smc_fid,
}
#endif
if
(
is_trng_fid
(
smc_fid
))
{
return
trng_smc_handler
(
smc_fid
,
x1
,
x2
,
x3
,
x4
,
cookie
,
handle
,
flags
);
}
switch
(
smc_fid
)
{
case
ARM_STD_SVC_CALL_COUNT
:
/*
...
...
services/std_svc/trng/trng_entropy_pool.c
0 → 100644
View file @
6080aac9
/*
* Copyright (c) 2021, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <lib/spinlock.h>
#include <plat/common/plat_trng.h>
/*
* # Entropy pool
* Note that the TRNG Firmware interface can request up to 192 bits of entropy
* in a single call or three 64bit words per call. We have 4 words in the pool
* so that when we have 1-63 bits in the pool, and we have a request for
* 192 bits of entropy, we don't have to throw out the leftover 1-63 bits of
* entropy.
*/
#define WORDS_IN_POOL (4)
static
uint64_t
entropy
[
WORDS_IN_POOL
];
/* index in bits of the first bit of usable entropy */
static
uint32_t
entropy_bit_index
;
/* then number of valid bits in the entropy pool */
static
uint32_t
entropy_bit_size
;
static
spinlock_t
trng_pool_lock
;
#define BITS_PER_WORD (sizeof(entropy[0]) * 8)
#define BITS_IN_POOL (WORDS_IN_POOL * BITS_PER_WORD)
#define ENTROPY_MIN_WORD (entropy_bit_index / BITS_PER_WORD)
#define ENTROPY_FREE_BIT (entropy_bit_size + entropy_bit_index)
#define _ENTROPY_FREE_WORD (ENTROPY_FREE_BIT / BITS_PER_WORD)
#define ENTROPY_FREE_INDEX (_ENTROPY_FREE_WORD % WORDS_IN_POOL)
/* ENTROPY_WORD_INDEX(0) includes leftover bits in the lower bits */
#define ENTROPY_WORD_INDEX(i) ((ENTROPY_MIN_WORD + i) % WORDS_IN_POOL)
/*
* Fill the entropy pool until we have at least as many bits as requested.
* Returns true after filling the pool, and false if the entropy source is out
* of entropy and the pool could not be filled.
* Assumes locks are taken.
*/
static
bool
trng_fill_entropy
(
uint32_t
nbits
)
{
while
(
nbits
>
entropy_bit_size
)
{
bool
valid
=
plat_get_entropy
(
&
entropy
[
ENTROPY_FREE_INDEX
]);
if
(
valid
)
{
entropy_bit_size
+=
BITS_PER_WORD
;
assert
(
entropy_bit_size
<=
BITS_IN_POOL
);
}
else
{
return
false
;
}
}
return
true
;
}
/*
* Pack entropy into the out buffer, filling and taking locks as needed.
* Returns true on success, false on failure.
*
* Note: out must have enough space for nbits of entropy
*/
bool
trng_pack_entropy
(
uint32_t
nbits
,
uint64_t
*
out
)
{
bool
success
=
true
;
spin_lock
(
&
trng_pool_lock
);
if
(
!
trng_fill_entropy
(
nbits
))
{
success
=
false
;
goto
out
;
}
const
unsigned
int
rshift
=
entropy_bit_index
%
BITS_PER_WORD
;
const
unsigned
int
lshift
=
BITS_PER_WORD
-
rshift
;
const
int
to_fill
=
((
nbits
+
BITS_PER_WORD
-
1
)
/
BITS_PER_WORD
);
int
word_i
;
for
(
word_i
=
0
;
word_i
<
to_fill
;
word_i
++
)
{
/*
* Repack the entropy from the pool into the passed in out
* buffer. This takes the lower bits from the valid upper bits
* of word_i and the upper bits from the lower bits of
* (word_i + 1).
*
* I found the following diagram useful. note: `e` represents
* valid entropy, ` ` represents invalid bits (not entropy) and
* `x` represents valid entropy that must not end up in the
* packed word.
*
* |---------entropy pool----------|
* C var |--(word_i + 1)-|----word_i-----|
* bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
* [x,x,e,e,e,e,e,e|e,e, , , , , , ]
* | [e,e,e,e,e,e,e,e] |
* | |--out[word_i]--| |
* lshift|---| |--rshift---|
*
* ==== Which is implemented as ====
*
* |---------entropy pool----------|
* C var |--(word_i + 1)-|----word_i-----|
* bit idx |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
* [x,x,e,e,e,e,e,e|e,e, , , , , , ]
* C expr << lshift >> rshift
* bit idx 5 4 3 2 1 0 7 6
* [e,e,e,e,e,e,0,0|0,0,0,0,0,0,e,e]
* ==== bit-wise or ====
* 5 4 3 2 1 0 7 6
* [e,e,e,e,e,e,e,e]
*/
out
[
word_i
]
=
0
;
out
[
word_i
]
|=
entropy
[
ENTROPY_WORD_INDEX
(
word_i
)]
>>
rshift
;
/*
* Note that a shift of 64 bits is treated as a shift of 0 bits.
* When the shift amount is the same as the BITS_PER_WORD, we
* don't want to include the next word of entropy, so we skip
* the `|=` operation.
*/
if
(
lshift
!=
BITS_PER_WORD
)
{
out
[
word_i
]
|=
entropy
[
ENTROPY_WORD_INDEX
(
word_i
+
1
)]
<<
lshift
;
}
}
const
uint64_t
mask
=
~
0ULL
>>
(
BITS_PER_WORD
-
(
nbits
%
BITS_PER_WORD
));
out
[
to_fill
-
1
]
&=
mask
;
entropy_bit_index
=
(
entropy_bit_index
+
nbits
)
%
BITS_IN_POOL
;
entropy_bit_size
-=
nbits
;
out:
spin_unlock
(
&
trng_pool_lock
);
return
success
;
}
void
trng_entropy_pool_setup
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
WORDS_IN_POOL
;
i
++
)
{
entropy
[
i
]
=
0
;
}
entropy_bit_index
=
0
;
entropy_bit_size
=
0
;
}
services/std_svc/trng/trng_entropy_pool.h
0 → 100644
View file @
6080aac9
/*
* Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TRNG_ENTROPY_POOL_H
#define TRNG_ENTROPY_POOL_H
#include <stdbool.h>
#include <stdint.h>
bool
trng_pack_entropy
(
uint32_t
nbits
,
uint64_t
*
out
);
void
trng_entropy_pool_setup
(
void
);
#endif
/* TRNG_ENTROPY_POOL_H */
services/std_svc/trng/trng_main.c
0 → 100644
View file @
6080aac9
/*
* Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <arch_features.h>
#include <lib/smccc.h>
#include <services/trng_svc.h>
#include <smccc_helpers.h>
#include <plat/common/plat_trng.h>
#include "trng_entropy_pool.h"
static
const
uuid_t
uuid_null
;
/* handle the RND call in SMC 32 bit mode */
static
uintptr_t
trng_rnd32
(
uint32_t
nbits
,
void
*
handle
)
{
uint32_t
mask
=
~
0U
;
uint64_t
ent
[
2
];
if
(
nbits
==
0U
||
nbits
>
96U
)
{
SMC_RET1
(
handle
,
TRNG_E_INVALID_PARAMS
);
}
if
(
!
trng_pack_entropy
(
nbits
,
&
ent
[
0
]))
{
SMC_RET1
(
handle
,
TRNG_E_NO_ENTROPY
);
}
if
((
nbits
%
32U
)
!=
0U
)
{
mask
>>=
32U
-
(
nbits
%
32U
);
}
switch
((
nbits
-
1U
)
/
32U
)
{
case
0
:
SMC_RET4
(
handle
,
TRNG_E_SUCCESS
,
0
,
0
,
ent
[
0
]
&
mask
);
break
;
/* unreachable */
case
1
:
SMC_RET4
(
handle
,
TRNG_E_SUCCESS
,
0
,
(
ent
[
0
]
>>
32
)
&
mask
,
ent
[
0
]
&
0xFFFFFFFF
);
break
;
/* unreachable */
case
2
:
SMC_RET4
(
handle
,
TRNG_E_SUCCESS
,
ent
[
1
]
&
mask
,
(
ent
[
0
]
>>
32
)
&
0xFFFFFFFF
,
ent
[
0
]
&
0xFFFFFFFF
);
break
;
/* unreachable */
default:
SMC_RET1
(
handle
,
TRNG_E_INVALID_PARAMS
);
break
;
/* unreachable */
}
}
/* handle the RND call in SMC 64 bit mode */
static
uintptr_t
trng_rnd64
(
uint32_t
nbits
,
void
*
handle
)
{
uint64_t
mask
=
~
0ULL
;
uint64_t
ent
[
3
];
if
(
nbits
==
0U
||
nbits
>
192U
)
{
SMC_RET1
(
handle
,
TRNG_E_INVALID_PARAMS
);
}
if
(
!
trng_pack_entropy
(
nbits
,
&
ent
[
0
]))
{
SMC_RET1
(
handle
,
TRNG_E_NO_ENTROPY
);
}
/* Mask off higher bits if only part of register requested */
if
((
nbits
%
64U
)
!=
0U
)
{
mask
>>=
64U
-
(
nbits
%
64U
);
}
switch
((
nbits
-
1U
)
/
64U
)
{
case
0
:
SMC_RET4
(
handle
,
TRNG_E_SUCCESS
,
0
,
0
,
ent
[
0
]
&
mask
);
break
;
/* unreachable */
case
1
:
SMC_RET4
(
handle
,
TRNG_E_SUCCESS
,
0
,
ent
[
1
]
&
mask
,
ent
[
0
]);
break
;
/* unreachable */
case
2
:
SMC_RET4
(
handle
,
TRNG_E_SUCCESS
,
ent
[
2
]
&
mask
,
ent
[
1
],
ent
[
0
]);
break
;
/* unreachable */
default:
SMC_RET1
(
handle
,
TRNG_E_INVALID_PARAMS
);
break
;
/* unreachable */
}
}
void
trng_setup
(
void
)
{
trng_entropy_pool_setup
();
plat_entropy_setup
();
}
/* Predicate indicating that a function id is part of TRNG */
bool
is_trng_fid
(
uint32_t
smc_fid
)
{
return
((
smc_fid
==
ARM_TRNG_VERSION
)
||
(
smc_fid
==
ARM_TRNG_FEATURES
)
||
(
smc_fid
==
ARM_TRNG_GET_UUID
)
||
(
smc_fid
==
ARM_TRNG_RND32
)
||
(
smc_fid
==
ARM_TRNG_RND64
));
}
uintptr_t
trng_smc_handler
(
uint32_t
smc_fid
,
u_register_t
x1
,
u_register_t
x2
,
u_register_t
x3
,
u_register_t
x4
,
void
*
cookie
,
void
*
handle
,
u_register_t
flags
)
{
if
(
!
memcmp
(
&
plat_trng_uuid
,
&
uuid_null
,
sizeof
(
uuid_t
)))
{
SMC_RET1
(
handle
,
TRNG_E_NOT_IMPLEMENTED
);
}
switch
(
smc_fid
)
{
case
ARM_TRNG_VERSION
:
SMC_RET1
(
handle
,
MAKE_SMCCC_VERSION
(
TRNG_VERSION_MAJOR
,
TRNG_VERSION_MINOR
));
break
;
/* unreachable */
case
ARM_TRNG_FEATURES
:
if
(
is_trng_fid
((
uint32_t
)
x1
))
{
SMC_RET1
(
handle
,
TRNG_E_SUCCESS
);
}
else
{
SMC_RET1
(
handle
,
TRNG_E_NOT_SUPPORTED
);
}
break
;
/* unreachable */
case
ARM_TRNG_GET_UUID
:
SMC_UUID_RET
(
handle
,
plat_trng_uuid
);
break
;
/* unreachable */
case
ARM_TRNG_RND32
:
return
trng_rnd32
((
uint32_t
)
x1
,
handle
);
case
ARM_TRNG_RND64
:
return
trng_rnd64
((
uint32_t
)
x1
,
handle
);
default:
WARN
(
"Unimplemented TRNG Service Call: 0x%x
\n
"
,
smc_fid
);
SMC_RET1
(
handle
,
TRNG_E_NOT_IMPLEMENTED
);
break
;
/* unreachable */
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment