mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-01 23:11:55 +00:00
Create syscalls to make possible using random APIs from user mode threads. These APIs can have different implementations, like using entropy driver or Xoroshiro128. Some of these implementations also have some globals to preserve state between calls. Make it run entire in user space would require user adding these globals to their memeory domains and/or grant access to entropy device. Syscalls simplify its usage. Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
125 lines
3.0 KiB
C
125 lines
3.0 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <sys/atomic.h>
|
|
#include <kernel.h>
|
|
#include <drivers/entropy.h>
|
|
#include <string.h>
|
|
|
|
static struct device *entropy_driver;
|
|
|
|
#if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
|
|
uint32_t z_impl_sys_rand32_get(void)
|
|
{
|
|
struct device *dev = entropy_driver;
|
|
uint32_t random_num;
|
|
int ret;
|
|
|
|
if (unlikely(!dev)) {
|
|
/* Only one entropy device exists, so this is safe even
|
|
* if the whole operation isn't atomic.
|
|
*/
|
|
dev = device_get_binding(DT_CHOSEN_ZEPHYR_ENTROPY_LABEL);
|
|
__ASSERT((dev != NULL),
|
|
"Device driver for %s (DT_CHOSEN_ZEPHYR_ENTROPY_LABEL) not found. "
|
|
"Check your build configuration!",
|
|
DT_CHOSEN_ZEPHYR_ENTROPY_LABEL);
|
|
entropy_driver = dev;
|
|
}
|
|
|
|
ret = entropy_get_entropy(dev, (uint8_t *)&random_num,
|
|
sizeof(random_num));
|
|
if (unlikely(ret < 0)) {
|
|
/* Use system timer in case the entropy device couldn't deliver
|
|
* 32-bit of data. There's not much that can be done in this
|
|
* situation. An __ASSERT() isn't used here as the HWRNG might
|
|
* still be gathering entropy during early boot situations.
|
|
*/
|
|
|
|
random_num = k_cycle_get_32();
|
|
}
|
|
|
|
return random_num;
|
|
}
|
|
#endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
|
|
|
|
static int rand_get(uint8_t *dst, size_t outlen, bool csrand)
|
|
{
|
|
struct device *dev = entropy_driver;
|
|
uint32_t random_num;
|
|
int ret;
|
|
|
|
if (unlikely(!dev)) {
|
|
/* Only one entropy device exists, so this is safe even
|
|
* if the whole operation isn't atomic.
|
|
*/
|
|
dev = device_get_binding(DT_CHOSEN_ZEPHYR_ENTROPY_LABEL);
|
|
__ASSERT((dev != NULL),
|
|
"Device driver for %s (DT_CHOSEN_ZEPHYR_ENTROPY_LABEL) not found. "
|
|
"Check your build configuration!",
|
|
DT_CHOSEN_ZEPHYR_ENTROPY_LABEL);
|
|
entropy_driver = dev;
|
|
}
|
|
|
|
ret = entropy_get_entropy(dev, dst, outlen);
|
|
|
|
if (unlikely(ret < 0)) {
|
|
/* Don't try to fill the buffer in case of
|
|
* cryptographically secure random numbers, just
|
|
* propagate the driver error.
|
|
*/
|
|
if (csrand) {
|
|
return ret;
|
|
}
|
|
|
|
/* Use system timer in case the entropy device couldn't deliver
|
|
* 32-bit of data. There's not much that can be done in this
|
|
* situation. An __ASSERT() isn't used here as the HWRNG might
|
|
* still be gathering entropy during early boot situations.
|
|
*/
|
|
|
|
uint32_t len = 0;
|
|
uint32_t blocksize = 4;
|
|
|
|
while (len < outlen) {
|
|
size_t copylen = outlen - len;
|
|
|
|
if (copylen > blocksize) {
|
|
copylen = blocksize;
|
|
}
|
|
|
|
random_num = k_cycle_get_32();
|
|
(void)memcpy(&(dst[len]), &random_num, copylen);
|
|
len += copylen;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
|
|
void z_impl_sys_rand_get(void *dst, size_t outlen)
|
|
{
|
|
rand_get(dst, outlen, false);
|
|
}
|
|
#endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
|
|
|
|
#if defined(CONFIG_HARDWARE_DEVICE_CS_GENERATOR)
|
|
|
|
int z_impl_sys_csrand_get(void *dst, size_t outlen)
|
|
{
|
|
if (rand_get(dst, outlen, true) != 0) {
|
|
/* Is it the only error it should return ? entropy_sam
|
|
* can return -ETIMEDOUT for example
|
|
*/
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_HARDWARE_DEVICE_CS_GENERATOR */
|