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