Skip to main content

mediatek_optical/receiver/programming/
reserved.rs

1//! The flash loop's reserved-region branches. These facts require incoming
2//! register/cell bindings and a complete loop proof before authorizing writes.
3use super::word;
4
5/// Complete checked skip branches and their register preconditions.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct ReservedSkips {
8    /// Start of the checked block.
9    pub address: u32,
10    /// First skipped destination offset.
11    pub first_start: u32,
12    /// Length added to both source and destination and removed from remaining.
13    pub first_length: u32,
14    /// Destination offset at which the final skip terminates programming.
15    pub final_start: u32,
16    /// Incoming r4 value needed by the final skip.
17    pub required_r4: u32,
18    /// Normal continuation, reached after the first skip or neither match.
19    pub continuation: u32,
20    /// Continuation after the final skip has set remaining length to zero.
21    pub finished: u32,
22}
23
24/// Check every instruction in both reserved-region branches. r7/r6/r5 must
25/// separately be established as destination/source/remaining pointers, and r4
26/// must equal 0x10000. Matching this component alone does not establish a loop.
27pub fn inspect_reserved_skips(bytes: &[u8], base: u32, start: u32) -> Option<ReservedSkips> {
28    if start & 1 != 0 || base & 1 != 0 {
29        return None;
30    }
31    // All data movement and both conditional joins are operand-bound. Only the
32    // final unconditional branch is relocatable; its destination is recorded.
33    let words = [
34        0x6838, 0x211d, 0x0409, 0x4288, 0xd10b, 0x6839, 0x2007, 0x0380, 0x1809, 0x6039, 0x6831,
35        0x1809, 0x6031, 0x6829, 0x1a08, 0x6028, 0xe00d, 0x6838, 0x211f, 0x0409, 0x4288, 0xd108,
36        0x6838, 0x1900, 0x6038, 0x6830, 0x1900, 0x6030, 0x2300, 0x602b,
37    ];
38    for (index, expected) in words.into_iter().enumerate() {
39        let at = start.checked_add(u32::try_from(index).ok()?.checked_mul(2)?)?;
40        if word(bytes, base, at)? != expected {
41            return None;
42        }
43    }
44    let branch_at = start.checked_add(60)?;
45    let instruction = word(bytes, base, branch_at)?;
46    if instruction & 0xf800 != 0xe000 {
47        return None;
48    }
49    let displacement = (i32::from(instruction & 0x7ff) << 21) >> 20;
50    let finished = u32::try_from(i64::from(branch_at) + 4 + i64::from(displacement)).ok()?;
51    let continuation = start.checked_add(62)?;
52    if finished <= continuation {
53        return None;
54    }
55    word(bytes, base, finished)?;
56    word(bytes, base, continuation)?;
57    Some(ReservedSkips {
58        address: start,
59        first_start: 0x1d0000,
60        first_length: 0x1c000,
61        final_start: 0x1f0000,
62        required_r4: 0x10000,
63        continuation,
64        finished,
65    })
66}