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