> u-boot is being corrupted following a Linux EFI callback to get_rng(). One of > the many footprints is a corruption of the EFI protocols linked list. > > Turns out that a request for >16 bytes of random data is broken into smaller > requests. > Those requests are fed in a loop to the CAAM RNG, which uses a job queue > ring for interaction. > > The problem is that in u-boot, the job queue descriptor is created only at > probe time, but then u-boot needs to endian swap the descriptor fed to the > CAAM RNG. So this corrupts the descriptor for the next iteration, since it > will > be blindly endian swapped yet again. > > Two issues arise. The number of words to endian swap is taken from the > input descriptor itself. > So on the second iteration, the length has been corrupted. This results in a > corruption past the end of the descriptor: whatever is after in memory is > corrupted. Second, some of the entries in the descriptors are DMA addresses. > So if the descriptor is still valid after swapping, the data at the corrupted > DMA > address is now corrupted. > > Linux properly initializes the descriptor for each iterations. > > Example: > Iteration 1: > desc[0]: 0xB0800005 > desc[1]: 0x82500002 > desc[2]: 0x60340010 > desc[3]: 0x00000000 > desc[4]: 0xFBC17380 > jr_enqueue: Start swap. > 0xb0800005 -> 0x050080b0 > 0x82500002 -> 0x02005082 > 0x60340010 -> 0x10003460 > 0x00000000 -> 0x00000000 > 0xfbc17380 -> 0x8073c1fb > > Iteration 2: > desc[0]: 0x050080B0 > desc[1]: 0x02005082 > desc[2]: 0x10003460 > desc[3]: 0x00000000 > desc[4]: 0x8073C1FB > jr_enqueue: Start swap. > 0x050080b0 -> 0xb0800005 > 0x02005082 -> 0x82500002 > 0x10003460 -> 0x60340010 > 0x00000000 -> 0x00000000 > 0x8073c1fb -> 0xfbc17380 > 0x00000000 -> 0x00000000 > 0x00000000 -> 0x00000000 > 0x00000000 -> 0x00000000 > 0x00000000 -> 0x00000000 > 0x00000000 -> 0x00000000 > 0x00000000 -> 0x00000000 > 0x00000000 -> 0x00000000 > ... > > Anthony >
Here is a proposed fix. The caam_rng_probe() init might not even be needed, but I left it there just in case. diff --git a/drivers/crypto/fsl/rng.c b/drivers/crypto/fsl/rng.c index 786a710f5fb..85544f931cb 100644 --- a/drivers/crypto/fsl/rng.c +++ b/drivers/crypto/fsl/rng.c @@ -23,11 +23,24 @@ struct caam_rng_priv { u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN); }; +static int caam_init_desc(struct caam_rng_priv *priv) +{ + ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN); + + inline_cnstr_jobdesc_rng(priv->desc, priv->data, + CAAM_RNG_MAX_FIFO_STORE_SIZE); + flush_dcache_range((unsigned long)priv->desc, + (unsigned long)priv->desc + size); + + return 0; +} + static int caam_rng_read_one(struct caam_rng_priv *priv) { int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN); int ret; + caam_init_desc(priv); ret = run_descriptor_jr(priv->desc); if (ret < 0) return -EIO; @@ -63,12 +76,8 @@ static int caam_rng_read(struct udevice *dev, void *data, size_t len) static int caam_rng_probe(struct udevice *dev) { struct caam_rng_priv *priv = dev_get_priv(dev); - ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN); - inline_cnstr_jobdesc_rng(priv->desc, priv->data, - CAAM_RNG_MAX_FIFO_STORE_SIZE); - flush_dcache_range((unsigned long)priv->desc, - (unsigned long)priv->desc + size); + caam_init_desc(priv); return 0; }