stm32: fix wait for RNG data

If no data was available to read then the loop would wait for an interrupt and skip to the next chunk without writing the current one.
This could cause the given slice to only be partially filled with random data.

Fixed by moving the wait to before actually writing data to the chunk.
This commit is contained in:
Olle Sandberg 2023-08-28 11:27:56 +02:00
parent 88146eb53e
commit fd739250ea

View File

@ -119,7 +119,31 @@ impl<'d, T: Instance> Rng<'d, T> {
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(4) { for chunk in dest.chunks_mut(4) {
let bits = T::regs().sr().read(); let mut bits = T::regs().sr().read();
if !bits.seis() && !bits.ceis() && !bits.drdy() {
// wait for interrupt
poll_fn(|cx| {
// quick check to avoid registration if already done.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
return Poll::Ready(());
}
RNG_WAKER.register(cx.waker());
T::regs().cr().modify(|reg| reg.set_ie(true));
// Need to check condition **after** `register` to avoid a race
// condition that would result in lost notifications.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
// Re-read the status register after wait.
bits = T::regs().sr().read()
}
if bits.seis() { if bits.seis() {
// in case of noise-source or seed error we try to recover here // in case of noise-source or seed error we try to recover here
// but we must not use the data in DR and we return an error // but we must not use the data in DR and we return an error
@ -143,26 +167,6 @@ impl<'d, T: Instance> Rng<'d, T> {
for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) {
*dest = *src *dest = *src
} }
} else {
// wait for interrupt
poll_fn(|cx| {
// quick check to avoid registration if already done.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
return Poll::Ready(());
}
RNG_WAKER.register(cx.waker());
T::regs().cr().modify(|reg| reg.set_ie(true));
// Need to check condition **after** `register` to avoid a race
// condition that would result in lost notifications.
let bits = T::regs().sr().read();
if bits.drdy() || bits.seis() || bits.ceis() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
} }
} }