1use snafu::Snafu;
2use unarm::{
3 ParsedIns,
4 args::{Argument, Reg, Register},
5};
6
7#[derive(Clone, Copy, Default, Debug)]
8pub enum SecureAreaState {
9 #[default]
10 Start,
11 Arg {
12 start: u32,
13 },
14 Return {
15 start: u32,
16 function: SwiFunction,
17 return_reg: Register,
18 },
19 ValidFunction(SecureAreaFunction),
20}
21
22impl SecureAreaState {
23 pub fn handle(self, address: u32, parsed_ins: &ParsedIns) -> Self {
24 let args = &parsed_ins.args;
25 match self {
26 Self::Start => match (parsed_ins.mnemonic, args[0], args[1]) {
27 ("swi", Argument::UImm(interrupt), Argument::None)
28 | ("svc", Argument::UImm(interrupt), Argument::None) => {
29 if let Ok(function) = interrupt.try_into() {
30 Self::Return { start: address, function, return_reg: Register::R0 }
31 } else {
32 Self::default()
33 }
34 }
35 ("mov", Argument::Reg(Reg { .. }), Argument::UImm(_)) => {
36 Self::Arg { start: address }
37 }
38 _ => Self::default(),
39 },
40 Self::Arg { start } => match (parsed_ins.mnemonic, args[0], args[1]) {
41 ("swi", Argument::UImm(interrupt), Argument::None)
42 | ("svc", Argument::UImm(interrupt), Argument::None) => {
43 if let Ok(function) = SwiFunction::try_from(interrupt) {
44 if function.allows_arg() {
45 Self::Return { start, function, return_reg: Register::R0 }
46 } else {
47 Self::Return { start: address, function, return_reg: Register::R0 }
49 }
50 } else {
51 Self::default()
52 }
53 }
54 _ => Self::default(),
55 },
56 Self::Return { start, function, return_reg } => {
57 match (parsed_ins.mnemonic, args[0], args[1], args[2]) {
58 (
59 "mov",
60 Argument::Reg(Reg { reg: dest, .. }),
61 Argument::Reg(Reg { reg: src, .. }),
62 Argument::None,
63 ) if dest == return_reg => Self::Return { start, function, return_reg: src },
64 (
65 "bx",
66 Argument::Reg(Reg { reg: Register::Lr, .. }),
67 Argument::None,
68 Argument::None,
69 ) => Self::ValidFunction(SecureAreaFunction {
70 function,
71 return_reg,
72 start,
73 end: address + 2,
74 }),
75 _ => Self::default(),
76 }
77 }
78 Self::ValidFunction { .. } => Self::default(),
79 }
80 }
81
82 pub fn get_function(self) -> Option<SecureAreaFunction> {
83 let Self::ValidFunction(function) = self else { return None };
84 Some(function)
85 }
86}
87
88#[derive(Clone, Copy, Debug)]
89pub enum SwiFunction {
90 SoftReset,
91 WaitByLoop,
92 IntrWait,
93 VBlankIntrWait,
94 Halt,
95 Div,
96 Mod,
97 CpuSet,
98 CpuFastSet,
99 Sqrt,
100 GetCRC16,
101 IsDebugger,
102 BitUnPack,
103 LZ77UnCompReadNormalWrite8bit,
104 LZ77UnCompReadByCallbackWrite16bit,
105 HuffUnCompReadByCallback,
106 RLUnCompReadNormalWrite8bit,
107 RLUnCompReadByCallbackWrite16bit,
108}
109
110impl SwiFunction {
111 pub fn interrupt_value(self) -> u32 {
112 match self {
113 Self::SoftReset => 0x0,
114 Self::WaitByLoop => 0x3,
115 Self::IntrWait => 0x4,
116 Self::VBlankIntrWait => 0x5,
117 Self::Halt => 0x6,
118 Self::Div | Self::Mod => 0x9,
119 Self::CpuSet => 0xb,
120 Self::CpuFastSet => 0xc,
121 Self::Sqrt => 0xd,
122 Self::GetCRC16 => 0xe,
123 Self::IsDebugger => 0xf,
124 Self::BitUnPack => 0x10,
125 Self::LZ77UnCompReadNormalWrite8bit => 0x11,
126 Self::LZ77UnCompReadByCallbackWrite16bit => 0x12,
127 Self::HuffUnCompReadByCallback => 0x13,
128 Self::RLUnCompReadNormalWrite8bit => 0x14,
129 Self::RLUnCompReadByCallbackWrite16bit => 0x15,
130 }
131 }
132
133 pub fn name(self, return_reg: Register) -> &'static str {
134 match (self, return_reg) {
135 (Self::SoftReset, _) => "SoftReset",
136 (Self::WaitByLoop, _) => "WaitByLoop",
137 (Self::IntrWait, _) => "IntrWait",
138 (Self::VBlankIntrWait, _) => "VBlankIntrWait",
139 (Self::Halt, _) => "Halt",
140 (Self::Div, Register::R1) => "Mod",
141 (Self::Div, _) => "Div",
142 (Self::Mod, _) => "Mod",
143 (Self::CpuSet, _) => "CpuSet",
144 (Self::CpuFastSet, _) => "CpuFastSet",
145 (Self::Sqrt, _) => "Sqrt",
146 (Self::GetCRC16, _) => "GetCRC16",
147 (Self::IsDebugger, _) => "IsDebugger",
148 (Self::BitUnPack, _) => "BitUnPack",
149 (Self::LZ77UnCompReadNormalWrite8bit, _) => "LZ77UnCompReadNormalWrite8bit",
150 (Self::LZ77UnCompReadByCallbackWrite16bit, _) => "LZ77UnCompReadByCallbackWrite16bit",
151 (Self::HuffUnCompReadByCallback, _) => "HuffUnCompReadByCallback",
152 (Self::RLUnCompReadNormalWrite8bit, _) => "RLUnCompReadNormalWrite8bit",
153 (Self::RLUnCompReadByCallbackWrite16bit, _) => "RLUnCompReadByCallbackWrite16bit",
154 }
155 }
156
157 pub fn allows_arg(self) -> bool {
158 matches!(self, Self::VBlankIntrWait)
159 }
160}
161
162#[derive(Debug, Snafu)]
163pub enum IntoSwiFunctionError {
164 #[snafu(display("unknown interrupt value {value:#x}"))]
165 UnknownInterrupt { value: u32 },
166}
167
168impl TryFrom<u32> for SwiFunction {
169 type Error = IntoSwiFunctionError;
170
171 fn try_from(value: u32) -> Result<Self, Self::Error> {
172 match value {
173 0x0 => Ok(Self::SoftReset),
174 0x3 => Ok(Self::WaitByLoop),
175 0x4 => Ok(Self::IntrWait),
176 0x5 => Ok(Self::VBlankIntrWait),
177 0x6 => Ok(Self::Halt),
178 0x9 => Ok(Self::Div),
179 0xb => Ok(Self::CpuSet),
180 0xc => Ok(Self::CpuFastSet),
181 0xd => Ok(Self::Sqrt),
182 0xe => Ok(Self::GetCRC16),
183 0xf => Ok(Self::IsDebugger),
184 0x10 => Ok(Self::BitUnPack),
185 0x11 => Ok(Self::LZ77UnCompReadNormalWrite8bit),
186 0x12 => Ok(Self::LZ77UnCompReadByCallbackWrite16bit),
187 0x13 => Ok(Self::HuffUnCompReadByCallback),
188 0x14 => Ok(Self::RLUnCompReadNormalWrite8bit),
189 0x15 => Ok(Self::RLUnCompReadByCallbackWrite16bit),
190 _ => UnknownInterruptSnafu { value }.fail(),
191 }
192 }
193}
194
195#[derive(Clone, Copy, Debug)]
196pub struct SecureAreaFunction {
197 function: SwiFunction,
198 return_reg: Register,
199 start: u32,
200 end: u32,
201}
202
203impl SecureAreaFunction {
204 pub fn name(&self) -> &'static str {
205 self.function.name(self.return_reg)
206 }
207
208 pub fn start(&self) -> u32 {
209 self.start
210 }
211
212 pub fn end(&self) -> u32 {
213 self.end
214 }
215}