1
use esp_sync::NonReentrantMutex;
2

            
3
use crate::{peripherals::RNG, soc::clocks};
4

            
5
// TODO: find a better place for these
6
#[inline]
7
#[cfg(all(soc_cpu_has_csr_pc, soc_cpu_csr_prv_mode_is_set))]
8
fn tee_enabled() -> bool {
9
    false
10
}
11

            
12
#[inline]
13
fn current_cpu_cycles() -> usize {
14
    cfg_select! {
15
        xtensa => xtensa_lx::timer::get_cycle_count() as usize,
16
        soc_cpu_has_csr_pc => {
17
            const PRV_M: usize = 3;
18
            macro_rules! read_csr_fn {
19
                ($fnname:ident, $csr:expr) => {
20
                    #[inline]
21
                    fn $fnname() -> usize {
22
                        let r: usize;
23

            
24
                        unsafe {
25
798
                            core::arch::asm!(concat!("csrrs {0}, ", $csr, ", x0"), out(reg) r);
26
                        }
27

            
28
                        return r;
29
                    }
30
                }
31
            }
32

            
33
            read_csr_fn!(read_pccr_machine, "0x7e2");
34
            read_csr_fn!(read_pccr_user, "0x802");
35

            
36
            fn read_prv_mode() -> usize {
37
                #[cfg(soc_cpu_csr_prv_mode_is_set)]
38
                if tee_enabled() {
39
                    read_csr_fn!(read_prv_m, property!("soc.cpu_csr_prv_mode", str));
40
                    return read_prv_m();
41
                }
42

            
43
                PRV_M
44
            }
45

            
46
            if read_prv_mode() == PRV_M {
47
                read_pccr_machine()
48
            } else {
49
                read_pccr_user()
50
            }
51
        }
52
        _ => riscv::register::mcycle::read(),
53
    }
54
}
55

            
56
static LAST_READ: NonReentrantMutex<usize> = NonReentrantMutex::new(0);
57

            
58
fn read_one(wait_cycles: usize) -> u32 {
59
    loop {
60
        let random = LAST_READ.with(|last_wait_start| {
61
            let now: usize = current_cpu_cycles();
62
798
            if now.wrapping_sub(*last_wait_start) >= wait_cycles {
63
798
                *last_wait_start = now;
64

            
65
                cfg_select! {
66
                    any(esp32c5, esp32c61) => Some(RNG::regs().rng_data_sync().read().bits()),
67
                    rng_is_lp_sys => Some(RNG::regs().rng_data().read().bits()),
68
                    esp32s31 => Some(RNG::regs().crc_sync_data().read().bits()),
69
                    _ => Some(RNG::regs().data().read().bits()),
70
                }
71
            } else {
72
                None
73
            }
74
        });
75
        if let Some(random) = random {
76
            return random;
77
        }
78
    }
79
}
80

            
81
14
pub(super) fn fill_ptr_range(data: *mut u8, len: usize) {
82
14
    let cpu_to_apb_freq_ratio = clocks::cpu_clk_frequency() / clocks::apb_clk_frequency();
83
14
    let wait_cycles = cpu_to_apb_freq_ratio as usize * property!("rng.apb_cycle_wait_num");
84

            
85
    let mut remaining = len;
86
    let mut dst = data;
87
798
    while remaining > 0 {
88
        let random_bytes = read_one(wait_cycles).to_le_bytes();
89
        let bytes_to_copy = random_bytes.len().min(remaining);
90
        unsafe {
91
            dst.copy_from_nonoverlapping(random_bytes.as_ptr(), bytes_to_copy);
92
            dst = dst.add(bytes_to_copy);
93
        }
94
798
        remaining -= bytes_to_copy;
95
    }
96
14
}