mediatek_optical/receiver/entry/application/
flags.rs1use super::{clear_site, Candidate, Prologue, Window};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct FlagCopy {
8 pub entry: u32,
10 pub end: u32,
12}
13
14fn jump(w: &Window<'_>, at: u32) -> Option<u32> {
15 if w.word(at)? & 0xf800 == 0xe000 {
16 w.branch(at)
17 } else {
18 Some(at)
19 }
20}
21
22pub fn inspect_flags(
26 bytes: &[u8],
27 address: u32,
28 candidate: &Candidate,
29 prelude: &Prologue,
30) -> Option<FlagCopy> {
31 if super::inspect(bytes, address)? != *candidate
34 || super::inspect_prologue(bytes, address, candidate)? != *prelude
35 {
36 return None;
37 }
38 let w = Window {
39 bytes,
40 base: address,
41 };
42 if clear_site(&w, candidate.entry.checked_add(2)?)? != candidate.entry {
43 return None;
44 }
45 let (base, _) = w.literal(candidate.entry)?;
46 let mut p = candidate.entry.checked_add(10)?;
47 let mut constants = prelude.constants;
48 let clear_temp = w.word(candidate.entry + 2)? & 7;
50 constants[clear_temp as usize] = None;
51 constants[base as usize] = None;
52 let mut cdb = prelude.cdb_registers & !(1 << base) & !(1 << clear_temp);
53 if let Some((reg, literal)) = w.literal(p) {
54 if literal != prelude.cdb_address || reg == base {
55 return None;
56 }
57 cdb |= 1 << reg;
58 constants[reg as usize] = None;
59 p = p.checked_add(2)?;
60 }
61 for bit in 0..4u16 {
62 p = jump(&w, p)?;
63 let load = w.word(p)?;
64 let temp = load & 7;
65 let source = (load >> 3) & 7;
66 if load != 0x7800 | (9 << 6) | (source << 3) | temp
67 || cdb & (1 << source) == 0
68 || temp == base
69 {
70 return None;
71 }
72 if w.word(p.checked_add(2)?)? != ((31 - bit) << 6) | (temp << 3) | temp {
73 return None;
74 }
75 constants[temp as usize] = None;
76 cdb &= !(1 << temp);
77 let branch = p.checked_add(4)?;
78 let condition = w.word(branch)? & 0xff00;
79 let skip_condition = if bit == 0 { 0xd000 } else { 0xd500 };
80 let set_condition = if bit == 0 { 0xd100 } else { 0xd400 };
81 let target = w.conditional(branch, condition)?;
82 let fallthrough = branch.checked_add(2)?;
83 let (mut set, skip) = if condition == skip_condition {
84 (fallthrough, target)
85 } else if condition == set_condition {
86 (target, fallthrough)
87 } else {
88 return None;
89 };
90 set = jump(&w, set)?;
91 let read = w.word(set)?;
93 let work = read & 7;
94 if read != 0x6980 | (base << 3) | work || work == base {
95 return None;
96 }
97 set = set.checked_add(2)?;
98 let before_set = constants;
99 let mut after_set = constants;
100 after_set[work as usize] = None;
101 if w.word(set)? & 0xf800 == 0x2000 {
102 let op = w.word(set)?;
103 let register = (op >> 8) & 7;
104 if register == base {
105 return None;
106 }
107 after_set[register as usize] = Some(u32::from(op & 255));
108 cdb &= !(1 << register);
109 set = set.checked_add(2)?;
110 }
111 let or = w.word(set)?;
112 if or & 0xffc0 != 0x4300 {
113 return None;
114 }
115 let destination = or & 7;
116 let operand = (or >> 3) & 7;
117 let constant = if destination == work {
118 operand
119 } else if operand == work {
120 destination
121 } else {
122 return None;
123 };
124 if after_set[constant as usize] != Some(1 << bit) || destination == base {
125 return None;
126 }
127 after_set[destination as usize] = None;
128 if w.word(set.checked_add(2)?)? != 0x6180 | (base << 3) | destination {
129 return None;
130 }
131 let next_set = jump(&w, set.checked_add(4)?)?;
132 let next_skip = jump(&w, skip)?;
133 if next_set != next_skip {
134 return None;
135 }
136 for reg in 0..8 {
137 constants[reg] = if before_set[reg] == after_set[reg] {
138 before_set[reg]
139 } else {
140 None
141 };
142 }
143 cdb &= !(1 << work) & !(1 << destination);
144 p = next_set;
145 }
146 p = jump(&w, p)?;
147 if w.word(p)? != 0xb000 | (prelude.stack_bytes / 4) || w.word(p.checked_add(2)?)? != 0xbdf0 {
148 return None;
149 }
150 Some(FlagCopy {
151 entry: candidate.entry,
152 end: p.checked_add(4)?,
153 })
154}