I have a MIPSEL ci20 dev-board that's suffering entropy depletion. The board has a JZ4780 SoC with an hardware rng (the register is mapped at address 0x100000DC). The Ingenic driver has some issue, so I wrote a userland program to read the register and replenish the pool.
After running the program I observed:
$ sudo ./ci20-rng.exe && for((i=1;i<=20;i+=1)); do (cat /proc/sys/kernel/random/entropy_avail; sleep 5); done 3968 3712 3456 3200 2944 2688 2432 2176 1920 1664 1408 1152 896 640 384 128 128 ... A similar question is What keeps draining entropy? The explanation of the drain mostly makes sense. I think its happening at too fast a rate given the explanations. But it seems like the drain should continue to 0, and not stabilize around 160 or 128.
Why does entropy_avail stabilize around 160 or 128?
The program below uses the ioctl(fd, RNDADDENTROPY, &entropy), where fd is a descriptor for /dev/random. entropy is the expected struct:
typedef struct { int bit_count; int byte_count; unsigned char buf[4096]; } entropy_t; Toggling of the control register (*ctrl = 0x00 and *ctrl = 0x01) followed by a delay is due to reading the JZ4780 Programmer's Manual. The idea is to write to the SC-ROM Controller but push it high for less than 1 second due to "... The maximum 2.5V supply time to VDDQ must be strictly controlled less than 1sec". I hope I am not hacking it too badly or misreading it.
Here's the program:
#include <stdio.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <linux/random.h> typedef struct { int bit_count; /* number of bits of entropy in data */ int byte_count; /* number of bytes of data in array */ unsigned char buf[4096]; } entropy_t; static int print_only; /* gcc -g2 -O2 -std=c99 ci20-rng.c -o ci20-rng.exe */ int main(int argc, char* argv[]) { int ret = 1, fd1 = -1, fd2 = -1, fd3 = -1; void *map1 = MAP_FAILED, *map2 = MAP_FAILED; const int PAGE_SIZE = sysconf(_SC_PAGESIZE); const int PAGE_MASK = ~(PAGE_SIZE - 1); #define CTRL_ADDR 0x100000D8 #define DATA_ADDR 0x100000DC if(argc >= 2) { if(0 == strcmp(argv[1], "-p") || 0 == strcmp(argv[1], "/p") || 0 == strcmp(argv[1], "--print")) print_only = 1; } fd1 = open("/dev/mem", O_RDWR | O_SYNC); if(fd1 == -1) { fprintf(stderr, "Failed to open /dev/mem for reading and writing (error %d)\n", errno); goto cleanup; } fd2 = open("/dev/mem", O_RDONLY | O_SYNC); if(fd2 == -1) { fprintf(stderr, "Failed to open /dev/mem for reading (error %d)\n", errno); goto cleanup; } fd3 = open("/dev/random", O_RDWR); if(fd3 == -1) { fprintf(stderr, "Failed to open /dev/random for writing (error %d)\n", errno); goto cleanup; } map1 = mmap (NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, CTRL_ADDR & PAGE_MASK); if(map1 == MAP_FAILED) { fprintf(stderr, "Failed to map 0x100000D8 for control (error %d)\n", errno); goto cleanup; } map2 = mmap (NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd2, DATA_ADDR & PAGE_MASK); if(map2 == MAP_FAILED) { fprintf(stderr, "Failed to map 0x100000DC for data (error %d)\n", errno); goto cleanup; } const int off1 = CTRL_ADDR % PAGE_SIZE; volatile uint32_t* volatile ctrl = (uint32_t*)((uint8_t*)map1+off1); const int off2 = DATA_ADDR % PAGE_SIZE; volatile uint32_t* volatile data = (uint32_t*)((uint8_t*)map2+off2); entropy_t entropy = { .bit_count = 4096*8, .byte_count = 4096 }; int count = 4096/4, idx = 0; while(count--) { /* If the delay from the loop drops too low, then we */ /* can watch the random values being shifted in. */ #define DELAY 5000 *ctrl = 0x01; for(unsigned int i = 0; i < DELAY; i++) { volatile uint32_t unused = *ctrl; } if(!print_only) { memcpy(entropy.buf+idx, (const void *)data, 4); idx += 4; } else { if(isatty(fileno(stdout))) fprintf(stdout, "0x%08x\n", *data); else write(fileno(stdout), (const void *)data, 4); } *ctrl = 0x00; for(unsigned int i = 0; i < DELAY; i++) { volatile uint32_t unused = *ctrl; } } if(!print_only) { int rc = ioctl(fd3, RNDADDENTROPY, &entropy); if(rc != 0) { fprintf(stderr, "Failed to add entropy (error %d)\n", errno); goto cleanup; } } ret = 0; cleanup: if(map2 != MAP_FAILED) { munmap(map2, PAGE_SIZE); } if(map1 != MAP_FAILED) { munmap(map1, PAGE_SIZE); } if(fd3 != -1) { close(fd3); } if(fd2 != -1) { close(fd2); } if(fd1 != -1) { close(fd1); } return ret; }
ioctlandRNDADDENTROPYto increase the count. The question was updated to include the program.