ds_decomp/analysis/
secure_area.rs

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}