LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

Linux hwrng以及ARM TRNG记录

关键词:hwrng,/dev/random,/dev/urandom,rngd,rngtest等。

 

Linux hwrng驱动比较简单,hwrng core注册设备提供sysfs几点给应用层使用。hwrnd driver提供具体硬件接口,然后注册到hwrng core中,以及往内核熵池提供随机数。

1. Linux hwrng框架

1.1 hwrng框架对外接口

 hwrng对外提供的API接口包括:注册接口、去注册接口、将硬件产生随机数加入到/dev/random接口。

其中注册和去注册接口分是否创建device_add接口两种。

/** Register a new Hardware Random Number Generator driver. */
extern int hwrng_register(struct hwrng *rng);
extern int devm_hwrng_register(struct device *dev, struct hwrng *rng);
/** Unregister a Hardware Random Number Generator driver. */
extern void hwrng_unregister(struct hwrng *rng);
extern void devm_hwrng_unregister(struct device *dve, struct hwrng *rng);
/** Feed random bits into the pool. */
extern void add_hwgenerator_randomness(const char *buffer, size_t count, size_t entropy);

 struct hwrng编写hwrnd硬件驱动的结构体,包含了操作函数集、熵质量、列表头、引用计数等。

一个驱动根据需要填写了结构体之后,即可通过hwrng_register()/devm_hwrng_register()注册到hwrng核心中,对/dev/hwrng设备的操作即可映射到注册的硬件。

struct hwrng {
    const char *name;
    int (*init)(struct hwrng *rng);--初始化回调函数。可为NULL。
    void (*cleanup)(struct hwrng *rng);--当rng的ref为0时被调用。可为NULL。
    int (*data_present)(struct hwrng *rng, int wait);--淘汰的接口。检查rng数据是否有效。
    int (*data_read)(struct hwrng *rng, u32 *data);--淘汰的接口。读取rng数据。
    int (*read)(struct hwrng *rng, void *data, size_t max, bool wait);--读取数据接口,替代data_present()和data_read()。
    unsigned long priv;
    unsigned short quality;--熵质量,0表示未知;1~1024越大表示越随机。

    /* internal. */
    struct list_head list;--插入rng_list中。
    struct kref ref;
    struct completion cleanup_done;
};

 1.2 rng core模块

rng core初始化时已经创建了/dev/hwrng设备,以及misc设备的一系列属性。

hwrng_modinit
  ->rng_buffer/rng_fillbuf--创建缓存。
->register_miscdev ->misc_register(&rng_miscdev)
      ->device_create_with_groups--创建字符设备,操作函数集为rng_chrdev_ops,groups为rng_dev_groups。

device_create_with_groups()创建设备位于/sys/devices/virtual/misc下,目录名对应miscdevice->name;并将groups下面的attr创建对应的节点。

对于hw_random而言创建:

  • rng_selected--是否由用户空间选择rng设备,1表示是,0表示没有设置过。
  • rng_current--当前rng设备名称,可以写入名称来选择指定rng设备。
  • rng_available--可用rng设备名称。
static struct miscdevice rng_miscdev = {
    .minor        = HWRNG_MINOR,
    .name        = RNG_MODULE_NAME,
    .nodename    = "hwrng",
    .fops        = &rng_chrdev_ops,
    .groups        = rng_dev_groups,
};

static const struct file_operations rng_chrdev_ops = {
    .owner        = THIS_MODULE,
    .open        = rng_dev_open,
    .read        = rng_dev_read,
    .llseek        = noop_llseek,
};

static const struct attribute_group *rng_dev_groups[];

rng_dev_read()是hwrng设备read()调用底层函数:

rng_dev_read
    ->get_current_rng
    ->rng_get_data
        ->hwrng->read--调用驱动实现的read()函数。
        ->hwrng->data_present--为NULL则表示数据一直可读。否则函数返回1表示数据可读,使用data_read()读取数据,0表示不可读。
        ->hwrng->data_read--在data_present为NULL,或返回1时被调用。
    ->copy_to_user--拷贝数据到用户空间缓存。

hwrng注册接口主要将当前hwrng加入到rng_list列表中,并选择熵质量最高的硬件作为当前随机数硬件设备。后续对/dev/hwrng的操作,会转换为对hwrng->read()等的调用。

devm_hwrng_register
    ->hwrng_register
        ->list_add_tail--将当前hwrng设备加入到rng_list中。
        ->set_current_rng--根据hwrng->quality选择合适的hwrng设备作为当前设备。
      ->hwrng_init
        ->rng->init--hwrng设备初始化。
        ->start_khwrngd
          ->hwrng_fillfn
->add_early_randomness ->rng_get_data--从硬件读取随机数。 ->add_device_randomness--将硬件产生的随机数添加到inpu_pool熵池中。 ->device_add--创建

2. hwrng驱动

编写hwrng驱动,最主要的工作就是填充struct hwrng结构体,其他诸如dts解析,中断注册和处理,调试接口等。

其中init()完成hwrng设备初始化,cleanup()完成设备关闭扫尾工作,核心是read()读取随机数。data_read()和data_present()是被淘汰的接口。

2.1 硬件资料

ARM TRNG规格书《Arm True Random Number Generator (TRNG) Technical Reference Manual Revision r0p0》,对应的裸驱程序《TZ-TRNG: TrustZone True Number Generator》。

3. /dev/random和/dev/urandom

/dev/random和/devurandom都提供了随机数读取接口,更多参考《初探 Linux kernel 亂數產生器 – random generator》,《What are /dev/random and /dev/urandom in Linux?》,《Linux随机数发生器 (betheme.net)》。

static const struct memdev {
    const char *name;
    umode_t mode;
    const struct file_operations *fops;
    fmode_t fmode;
} devlist[] = {
     [8] = { "random", 0666, &random_fops, 0 },
     [9] = { "urandom", 0666, &urandom_fops, 0 },
};

const struct file_operations random_fops = {
    .read  = random_read,
    .write = random_write,
    .poll  = random_poll,
    .unlocked_ioctl = random_ioctl,
    .fasync = random_fasync,
    .llseek = noop_llseek,
};

const struct file_operations urandom_fops = {
    .read  = urandom_read,
    .write = random_write,
    .unlocked_ioctl = random_ioctl,
    .fasync = random_fasync,
    .llseek = noop_llseek,
};

另外还提供了getrandom系统调用。

4. hwrng测试程序

通过dd读取/dev/hwrng数据到指定文件:

dd if=/dev/hrrng of=rng.dat bs=1024 count=1

安装rng-tools,里面包含rngd和rngtest两个程序。

rngd作为守护进程,从/dev/hwrng中读取随机数,喂到内核熵池中。

rngd --rng-device=/dev/hwrng 

rngtest使用FIPS 140-2协议对从/dev/hwrng获取的数据进行检查。

cat /dev/hwrng | rngtest -c 1000

参考资料:《3.4. Using the Random Number Generator Red Hat Enterprise Linux 6》《》

posted on 2023-06-16 23:59  ArnoldLu  阅读(1118)  评论(1编辑  收藏  举报

导航