Jeffrey

Forum Replies Created

Viewing 1 post (of 1 total)
  • Author
    Posts

  • Jeffrey
    Participant

    Thanks for investigating the issue Zubair.

    > The description of those registers is cryptic unfortunately. It looks like one is to enable the hwrng. And the other is a 32 bit register to read the hwrng. I tried using /dev/mem to play with those but couldn’t come up with any conclusive results to share.

    Yeah, I know what you mean. There could be more information available.

    The following program is what I came up with for a test case. It enables the JZ4780’s RNG and reads 16 random values. It uses a loop to introduce a delay because I could not get usleep or nanosleep to compile as expected.

    The program needs sudo to map in the memory from /dev/mem. (I’m not sure mapping /dev/mem is considered a best practice, but that’s another issue).

    Unfortunately, I don’t know enough about Linux drivers to do anything more with it. I have an old book on them, but it does not cover the new kernels or consider the linux-crypto.

    /* ci20-rng.c  – userland program to read random values from RNG register mapped at 0x100000DC.  */
    /*               written and placed in public domain by Jeffrey Walton. The next step is to wrap */
    /*               it in a Linux driver, or fold it into rng-tools so /dev/random stops suffering  */
    /*               entropy depletion.                                                              */
    
    #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>
    
    #define DEV_RANDOM_BYTES 512
    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[DEV_RANDOM_BYTES];
    } 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 &amp; 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 &amp; 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 = DEV_RANDOM_BYTES*8, .byte_count = DEV_RANDOM_BYTES };
        int count = DEV_RANDOM_BYTES/sizeof(uint32_t), idx = 0;
    
        while(count–)
        {
            /* If the delay from the loop drops too low, then we can watch the random     */
            /*  values being shifted in. If the delay is 0, then the value appears fixed. */
            #define DELAY 5000
    
            const uint32_t old_ctrl = *ctrl;
            *ctrl = old_ctrl | 0x01;
            for(unsigned int i = 0; i < DELAY; i++) {
                volatile uint32_t unused = *ctrl;
            }
    
            /* If not printing to screen or file, then add them to /dev/random */
            if(!print_only)
            {
                /* Copy into struct entropy_t buffer */
                memcpy(entropy.buf+idx, (const void *)data, 4);
                idx += 4;
            }
            else
            {
                /* If print to screen, then print one per line in ASCII.   */
                /* If print to file, then print a stream of binary. Piping */
                /* streams binary, so 'wc -l' does not work as expected.   */
                if(isatty(fileno(stdout)))
                    fprintf(stdout, "0x%08xn", *data);
                else
                    write(fileno(stdout), (const void *)data, 4);
            }
    
            *ctrl = old_ctrl;
            for(unsigned int i = 0; i < DELAY; i++) {
                volatile uint32_t unused = *ctrl;
            }
        }
    
        /* Add the bytes to /dev/random. A real driver should probably extract the entropy */
        /* at this point using HMAC or HKDF since its directly added to /dev/random.       */
        if(!print_only)
        {
            int rc = ioctl(fd3, RNDADDENTROPY, &amp;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;
    }
    
Viewing 1 post (of 1 total)