The hardware RNG on the Raspberry Pi 4 differs slightly from the version found in the Pi 3. This patch extends the existing bcm2835_rng.c driver to function on the Pi4. However, I do not expose all of the register debug facilities that are available on the pi 3 driver.
Tested on my Pi 4, the numbers given appear random, but I have not had time to generate a statistical analysis of the collected numbers. @kevans stated he would check the driver still functions correctly on a Pi 3.
No real objections from me either; I'm unfamiliar with the hardware and the random(4) integration seems mostly good. Some nits and suggestions below.
And perhaps const
Should the RND_WARM_CNT mask be part of sc->conf?
I'm not sure this is ever what we want?
Is this something that can happen, and do we have reason to believe this procedure will fix the RNG?
Is it possible the RNG might continue producing output after we've observed zero bytes available? I.e., we're just consuming it too fast but it'll continue to produce entropy bytes at some rate?
I'd suggest wrapping this in a subroutine that submits multiple random_harvest_queue() invocations with at most HARVESTSIZE * sizeof(uint32_t) (i.e., 8) bytes per invocation. Otherwise, the high quality random data will be squashed together into at most 8 bytes, which is a pretty big waste if we're pulling e.g. 32 bytes from this device. Maybe random(4) should provide an API for high quality sources instead, I don't know.
(Or, uh, sizeof(((struct harvest_event *)0)->he_entropy), but that's kind of a big ugly expression.)
Maybe just (void *), especially if it unwraps the line.
Should we default to 2x mode (but allow it to be disabled with the tunable? Is there some reason to believe 2x mode will be a worse default (higher power draw, perhaps)?
Thanks for reviewing this.
I don't know, that was the original algorithm. I haven't seen it in action.
Are you saying that random_harvest_queue() only takes some of the random data supplied? If I use the API to submit 10 MB of random data, it effectively only extracts 8 bytes of randomness?
I don't know, you'd have to ask the original author. It doesn't seem to exist on the newer 2838 chip, at least, as far as I could figure out. I agree the toggle seems like a complication that probably offers zero value.
I wrote this patch, which edits the existing BCM2835 driver from mainline FreeBSD, to add support for the BCM2838 chip. I did not write that original driver. This patch does not intend to affect the existing behaviour of the "bcmrng.2xspeed" mode on the BCM2835 chip. The "2x speed" mode seems like a weird quirk, but I don't want to comment authoritatively on whether it should exist or not, nor whether it should be default enabled. The "2x speed" mode does not appear to exist on the BCM2838 chip, which is why I moved it under an if-block in this patch.
To be clear, it is a bad API. I'm not defending it, just telling you where the foot-gun is so you can avoid it.
(It's a red herring here but: yes, I meant the original author of the patch, not the file. I believe you may be able to submit patches on behalf of others; you obviously need at least their permission and license of copyright.)
I was confused when you referred me to the "original author" for questions about what I perceived as changes you had authored. Your latest comment makes clear that the revision is just selectively disabling the existing behavior on the new chip, which doesn't have that functionality. That's perfectly fine! (Probably I should have noticed that when I was first reading the change — my bad.) It also would have been a less confusing answer to the original (confused) question.
If a committer is needed, I'm happy to oblige, but I'll need testing time, and for that I need to build and boot. If Someone Else(™) can assure me that this works, I'll speed it up a bit.
Mostly looks good to me. A few style nits below. One thing that definitely must be fixed (pointer arith error). Thanks!
This probably needs to be a const pointer, or I doubt this will compile.
Probably makes sense to use uint32_t for size, too, given it is assigned either cnt or chunk_size (both uint32_t). (Yes, these are the same size on all FreeBSD archs, but I think it is best to be consistent.)
sometimes spelled MIN(cnt, chunk_size) (sys/param.h).
This math is wrong. Due to pointer arithmetic rules, this will increment sc_buf_chunk by a factor of sizeof(uint32_t) more than you intend.
I would suggest just using char *sc_buf_chunk and perhaps initializing it with a (void *)sc->sc_buf cast.
I think the message text might be less confusing if it said "sc->conf == NULL". Not a big deal.
LGTM. A few minor style nits.
One thing it might be nice to do before commit is to grab some raw output from the generator and run it through a tester. PractRand is pretty fast (on server-class hardware, not Rpi) and should be fed as much data as you can stand (I don't know how fast the random source is, but "many GBs" is an acceptable amount of input to PractRand, if it doesn't take too long to gather). The runtime of PractRand itself is something like a few minutes for GB-length inputs.
NIST has their SP800-90B Entropy estimator: https://github.com/usnistgov/SP800-90B_EntropyAssessment . This test is very slow (you'd want to run it on a fast amd64 machine, not on rpi directly, and it takes several hours) but gives some estimate of min-entropy. For this one, I'd only feed it about 1 MB of RNG output.
Usually we put const before the underlying type name (const struct bcm_rng_conf *). No functional difference. Style(9) also wants a space before the *.
style(9) nit: space between void and *
Style nit: const void *