不管是否支持hwrng 都可以看到/dev/hwrng 这个字符设备,如果有真正的hwrng,则只是增加这个hwrng的随机性而已,同一个hwrng不能重复注册,而且会根据每个hwrng的quality 来选择一个质量最好的hwrng。
这里举例如下:drivers\crypto\hisilicon\trng.c
probe 中的核心代码如下:
trng->rng.name = pdev->name;
#这里提供的读取硬件随机数的方法
trng->rng.read = hisi_trng_read;
#这里设置质量,在下面的函数中会选择质量高的,也就是越随机的作为当前的hwrng
trng->rng.quality = HISI_TRNG_QUALITY;
ret = devm_hwrng_register(&pdev->dev, &trng->rng);
if (ret) {
dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
goto err_crypto_unregister;
}
int devm_hwrng_register(struct device *dev, struct hwrng *rng)
{
struct hwrng **ptr;
int error;
ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
#核心函数,想系统中/dev/hwrng 提供真随机数
error = hwrng_register(rng);
if (error) {
devres_free(ptr);
return error;
}
*ptr = rng;
#将这个设备增加到一个list中
devres_add(dev, ptr);
return 0;
}
int hwrng_register(struct hwrng *rng)
{
int err = -EINVAL;
struct hwrng *tmp;
struct list_head *rng_list_ptr;
bool is_new_current = false;
#注册的随机数生成器必须有name和提供读取随机数的方法
if (!rng->name || (!rng->data_read && !rng->read))
goto out;
mutex_lock(&rng_mutex);
/* Must not register two RNGs with the same name. */
err = -EEXIST;
#检查这个名字的随机数生成器是否已经注册过,所以前面一定要检查这个随机数要有名字,这里用名字来判断
#一个随机数是否注册过
list_for_each_entry(tmp, &rng_list, list) {
if (strcmp(tmp->name, rng->name) == 0)
goto out_unlock;
}
init_completion(&rng->cleanup_done);
complete(&rng->cleanup_done);
#更加qulity 对目前已有的随机数生成器进行排序,qulity越大说明产生的随机数越随机。
/* rng_list is sorted by decreasing quality */
list_for_each(rng_list_ptr, &rng_list) {
tmp = list_entry(rng_list_ptr, struct hwrng, list);
if (tmp->quality < rng->quality)
break;
}
list_add_tail(&rng->list, rng_list_ptr);
#设置当前的随机数生成器
if (!current_rng ||
(!cur_rng_set_by_user && rng->quality > current_rng->quality)) {
/*
* Set new rng as current as the new rng source
* provides better entropy quality and was not
* chosen by userspace.
*/
err = set_current_rng(rng);
if (err)
goto out_unlock;
/* to use current_rng in add_early_randomness() we need
* to take a ref
*/
is_new_current = true;
kref_get(&rng->ref);
}
mutex_unlock(&rng_mutex);
if (is_new_current || !rng->init) {
/*
* Use a new device's input to add some randomness to
* the system. If this rng device isn't going to be
* used right away, its init function hasn't been
* called yet by set_current_rng(); so only use the
* randomness from devices that don't need an init callback
*/
#第一次增加随机数
add_early_randomness(rng);
}
if (is_new_current)
put_rng(rng);
return 0;
out_unlock:
mutex_unlock(&rng_mutex);
out:
return err;
}