1use core::result::Result;
2use crate::{drivers::clocks::Clocks, typestates::init_state};
4use core::ptr::copy_nonoverlapping;
5
6#[derive(Copy, Clone, PartialEq)]
7pub enum KeyType {
8 Sbkek = 0x00,
9 User = 0x01,
10 Uds = 0x02,
11 PrinceRegion0 = 0x03,
12 PrinceRegion1 = 0x04,
13 PrinceRegion2 = 0x05,
14}
15
16#[derive(Copy, Clone)]
17#[repr(C)]
18pub struct IvCodePrinceRegion {
19 pub keycode_header: u32,
20 pub iv: [u8; 52],
21}
22
23#[derive(Copy, Clone)]
24#[repr(C)]
25pub struct Cfpa {
26 pub header: u32,
27 pub version: u32,
28 pub secure_fw_version: u32,
29 pub ns_fw_version: u32,
30 pub image_key_revoke: u32,
31
32 reserved0: [u8; 4],
33
34 pub rotkh_revoke: u32,
35 vendor_usage: u32,
36 pub dcfg_ns_pin: u32,
37 pub dcfg_ns_dflt: u32,
38 enable_fa_mode: u32,
39
40 reserved1: [u8; 4],
41 pub iv_code_prince_region: [IvCodePrinceRegion; 3],
45
46 reserved2: [u8; 40],
48 pub customer_data: [u8; 224],
49 sha256: [u8; 32],
50}
51
52impl Cfpa {
53 pub fn key_provisioned(&self, key_type: KeyType) -> bool {
55 match key_type {
56 KeyType::PrinceRegion0 | KeyType::PrinceRegion1 | KeyType::PrinceRegion2 => {
58 let mut iv_or = 0;
59 let index = (key_type as usize) - (KeyType::PrinceRegion0 as usize);
60 for i in 0..self.iv_code_prince_region[index].iv.len() {
61 iv_or |= self.iv_code_prince_region[index].iv[i];
62 }
63
64 iv_or != 0
65 }
66 _ => false,
68 }
69 }
70}
71
72#[derive(Copy, Clone)]
73#[repr(C)]
74pub struct Cmpa {
75 pub boot_cfg: u32,
76 pub spi_flash_cfg: u32,
77 pub usb_vid: u16,
78 pub usb_pid: u16,
79 pub sdio_cfg: u32,
80 pub dcfg_pin: u32,
81 pub dcfg_dflt: u32,
82 pub dap_vendor_usage: u32,
83 pub secure_boot_cfg: u32,
84 pub prince_base_addr: u32,
85 pub prince_sr: [u32; 3],
86 reserved0: [u8; 32],
87
88 pub rotkh: [u8; 32],
89 reserved1: [u8; 144],
90
91 pub customer_data: [u8; 224],
92 sha256: [u8; 32],
93}
94
95const _: () = {
97 assert!(size_of::<Cmpa>() == 512);
98 assert!(size_of::<Cfpa>() == 512);
99};
100
101#[repr(C)]
103struct BootloaderTree {
104 run_bootloader: extern "C" fn(arg: &u32) -> (),
106
107 version: u32,
108 copyright: *const char,
109 reserved0: u32,
110
111 flash_driver: &'static FlashDriverInterface,
112
113 reserved_kb_interface: u32,
115 reserved1: [u32; 4],
116 reserved_skboot_authenticate_interface: u32,
117}
118
119#[repr(C)]
120struct FlashDriverInterface {
121 version: u32,
122 flash_init: unsafe extern "C" fn(config: &mut FlashConfig) -> u32,
123 flash_erase: unsafe extern "C" fn(
124 config: &mut FlashConfig,
125 start: u32,
126 length_in_bytes: u32,
127 key: u32,
128 ) -> u32,
129 flash_program: unsafe extern "C" fn(
130 config: &mut FlashConfig,
131 start: u32,
132 src: *const u8,
133 length_in_bytes: u32,
134 ) -> u32,
135 flash_verify_erase:
136 unsafe extern "C" fn(config: &mut FlashConfig, start: u32, length_in_bytes: u32) -> u32,
137 flash_verify_program: unsafe extern "C" fn(
138 config: &mut FlashConfig,
139 start: u32,
140 length_in_bytes: u32,
141 expected_data: *const u8,
142 failed_address: &mut u32,
143 failed_data: &mut u32,
144 ) -> u32,
145
146 flash_get_property:
147 unsafe extern "C" fn(config: &mut FlashConfig, tag: u32, value: &mut u32) -> u32,
148 reserved: [u32; 3],
149
150 ffr_init: unsafe extern "C" fn(config: &mut FlashConfig) -> u32,
151 ffr_lock_all: unsafe extern "C" fn(config: &mut FlashConfig) -> u32,
152 ffr_cust_factory_page_write: unsafe extern "C" fn(
153 config: &mut FlashConfig,
154 page_data: *const u8,
155 seal_part: bool,
156 ) -> u32,
157 ffr_get_uuid: unsafe extern "C" fn(config: &mut FlashConfig, uuid: *mut u8) -> u32,
158 ffr_get_customer_data: unsafe extern "C" fn(
159 config: &mut FlashConfig,
160 pData: *mut u8,
161 offset: u32,
162 len: u32,
163 ) -> u32,
164
165 ffr_keystore_write: unsafe extern "C" fn(config: &mut FlashConfig) -> u32,
167 ffr_keystore_get_ac:
168 unsafe extern "C" fn(config: &mut FlashConfig, activation_code: *mut u8) -> u32,
169 ffr_keystore_get_kc:
170 unsafe extern "C" fn(config: &mut FlashConfig, keycode: *mut u8, key_index: u32) -> u32,
171
172 ffr_infield_page_write:
173 unsafe extern "C" fn(config: &mut FlashConfig, page_data: *const u8, valid_len: u32) -> u32,
174 ffr_get_customer_infield_data: unsafe extern "C" fn(
175 config: &mut FlashConfig,
176 page_data: *mut u8,
177 offset: u32,
178 len: u32,
179 ) -> u32,
180}
181
182#[repr(C)]
183pub struct FlashFfrConfig {
184 pub ffr_block_base: u32,
185 pub ffr_total_size: u32,
186 pub ffr_page_size: u32,
187 pub cfpa_page_version: u32,
188 pub cfpa_page_offset: u32,
189}
190
191#[repr(C)]
192pub struct FlashModeConfig {
193 sys_freq_in_mhz: u32,
194 single_word_mode: u32,
195 write_mode: u32,
196 read_mode: u32,
197}
198
199#[repr(C)]
200pub struct FlashConfig {
201 pflash_block_base: u32,
202 pflash_total_size: u32,
203 pflash_block_count: u32,
204 pflash_page_size: u32,
205
206 pflash_sector_size: u32,
207
208 pub ffr_config: FlashFfrConfig,
209 pub mode_config: FlashModeConfig,
210}
211
212impl FlashConfig {
213 fn new(system_clock_freq_in_mhz: u32) -> FlashConfig {
214 let flash_ffr_config = FlashFfrConfig {
215 ffr_block_base: 0,
216 ffr_total_size: 0,
217 ffr_page_size: 0,
218 cfpa_page_version: 0,
219 cfpa_page_offset: 0,
220 };
221 let flash_mode_config = FlashModeConfig {
222 sys_freq_in_mhz: system_clock_freq_in_mhz,
223 single_word_mode: 0,
224 write_mode: 0,
225 read_mode: 0,
226 };
227 FlashConfig {
228 pflash_block_base: 0,
229 pflash_total_size: 0,
230 pflash_block_count: 0,
231 pflash_page_size: 0,
232 pflash_sector_size: 0,
233 ffr_config: flash_ffr_config,
234 mode_config: flash_mode_config,
235 }
236 }
237}
238
239pub struct Pfr<State = init_state::Unknown> {
240 pub flash_config: FlashConfig,
241 pub _state: State,
242}
243impl<State> Pfr<State> {
244 fn bootloader_api_tree() -> &'static mut BootloaderTree {
245 #[allow(clippy::transmute_ptr_to_ref)]
246 unsafe {
247 core::mem::transmute(0x130010f0u32 as *const ())
248 }
249 }
250 fn check_error(err: u32) -> Result<(), u32> {
251 if err == 0 {
252 Ok(())
253 } else {
254 Err(err)
255 }
256 }
257}
258
259impl Default for Pfr {
260 fn default() -> Self {
261 Self::new()
262 }
263}
264impl Pfr {
265 pub fn new() -> Self {
266 Self {
267 flash_config: FlashConfig::new(0),
268 _state: init_state::Unknown,
269 }
270 }
271
272 pub fn enabled(mut self, clock_config: &Clocks) -> Result<Pfr<init_state::Enabled>, u32> {
273 self.flash_config = FlashConfig::new(clock_config.system_frequency.0 / 1_000_000);
274
275 let flash_init = Self::bootloader_api_tree().flash_driver.flash_init;
276 let ffr_init = Self::bootloader_api_tree().flash_driver.ffr_init;
277
278 Self::check_error(unsafe { flash_init(&mut self.flash_config) })?;
279 Self::check_error(unsafe { ffr_init(&mut self.flash_config) })?;
280
281 Ok(Pfr {
282 flash_config: self.flash_config,
283 _state: init_state::Enabled(()),
284 })
285 }
286}
287
288impl Pfr<init_state::Enabled> {
289 pub fn read_cmpa(&mut self) -> Result<Cmpa, u32> {
290 let mut cmpa_bytes = [0u8; 512];
291
292 let ffr_get_customer_data = Self::bootloader_api_tree()
293 .flash_driver
294 .ffr_get_customer_data;
295
296 Self::check_error(unsafe {
297 ffr_get_customer_data(&mut self.flash_config, cmpa_bytes.as_mut_ptr(), 0, 512)
298 })?;
299 let cmpa: &Cmpa = unsafe { &*(cmpa_bytes.as_ptr() as *const _) };
303
304 Ok(*cmpa)
305 }
306
307 pub fn cmpa_customer_data(&mut self) -> &'static [u8] {
309 let cmpa_ptr = (0x9E500) as *const u8;
310 let slice = unsafe { core::slice::from_raw_parts(cmpa_ptr, 224) };
311 slice
312 }
313
314 pub fn read_cfpa_with_bootrom(&mut self) -> Result<Cfpa, u32> {
323 let mut cfpa_bytes = [0u8; 512];
324
325 let ffr_get_customer_infield_data = Self::bootloader_api_tree()
326 .flash_driver
327 .ffr_get_customer_infield_data;
328
329 Self::check_error(unsafe {
330 ffr_get_customer_infield_data(&mut self.flash_config, cfpa_bytes.as_mut_ptr(), 0, 512)
331 })?;
332 let cfpa: &Cfpa = unsafe { &*(cfpa_bytes.as_ptr() as *const _) };
336
337 Ok(*cfpa)
338 }
339
340 pub fn read_latest_cfpa(&mut self) -> Result<Cfpa, u32> {
344 use core::ptr::copy_nonoverlapping;
345 let mut cfpa_bytes = [0u32; 128];
346
347 let ping_ptr = (0x0009_DE00 + 512) as *const u32;
348 let pong_ptr = (0x0009_DE00 + 512 + 512) as *const u32;
349
350 let ping_version: u32 = unsafe { *(ping_ptr).offset(1) };
351 let pong_version: u32 = unsafe { *(pong_ptr).offset(1) };
352
353 let cfpa_ptr: *const u32 = if ping_version > pong_version {
354 ping_ptr
355 } else {
356 pong_ptr
357 };
358
359 unsafe {
360 copy_nonoverlapping(cfpa_ptr, cfpa_bytes.as_mut_ptr(), 128);
361 }
362
363 let cfpa: &Cfpa = unsafe { &*(cfpa_bytes.as_ptr() as *const _) };
364
365 Ok(*cfpa)
366 }
367
368 pub fn read_cfpa_ping(&mut self) -> Result<Cfpa, u32> {
369 let mut cfpa_bytes = [0u32; 128];
370
371 const CFPA_PTR: *const u32 = (0x0009_DE00 + 512) as *const u32;
372 unsafe {
373 copy_nonoverlapping(CFPA_PTR, cfpa_bytes.as_mut_ptr(), 128);
374 }
375
376 let cfpa: &Cfpa = unsafe { &*(cfpa_bytes.as_ptr() as *const _) };
377
378 Ok(*cfpa)
379 }
380
381 pub fn read_cfpa_pong(&mut self) -> Result<Cfpa, u32> {
382 let mut cfpa_bytes = [0u32; 128];
383
384 const CFPA_PTR: *const u32 = (0x0009_DE00 + 512 + 512) as *const u32;
385 unsafe {
386 copy_nonoverlapping(CFPA_PTR, cfpa_bytes.as_mut_ptr(), 128);
387 }
388
389 let cfpa: &Cfpa = unsafe { &*(cfpa_bytes.as_ptr() as *const _) };
390
391 Ok(*cfpa)
392 }
393
394 pub fn write_cfpa(&mut self, cfpa: &Cfpa) -> Result<(), u32> {
395 let ffr_infield_page_write = Self::bootloader_api_tree()
396 .flash_driver
397 .ffr_infield_page_write;
398 let cfpa_bytes: *const u8 = unsafe { core::mem::transmute(cfpa as *const Cfpa) };
399 Self::check_error(unsafe {
400 ffr_infield_page_write(&mut self.flash_config, cfpa_bytes, 512)
401 })?;
402 Ok(())
403 }
404
405 pub fn read_key_code(&mut self, key_type: KeyType) -> Result<[u8; 52], u32> {
406 let mut bytes = [0u8; 52];
407 let ffr_keystore_get_kc = Self::bootloader_api_tree().flash_driver.ffr_keystore_get_kc;
408
409 Self::check_error(unsafe {
410 ffr_keystore_get_kc(&mut self.flash_config, bytes.as_mut_ptr(), key_type as u32)
411 })?;
412
413 Ok(bytes)
414 }
415
416 pub fn read_activation_code(&mut self) -> Result<[u8; 1192], u32> {
417 let mut ac = [0u8; 1192];
418 let ffr_keystore_get_ac = Self::bootloader_api_tree().flash_driver.ffr_keystore_get_ac;
419 Self::check_error(unsafe { ffr_keystore_get_ac(&mut self.flash_config, ac.as_mut_ptr()) })?;
420
421 Ok(ac)
422 }
423
424 pub fn lock_all(&mut self) -> Result<(), u32> {
426 let ffr_lock_all = Self::bootloader_api_tree().flash_driver.ffr_lock_all;
427 Self::check_error(unsafe { ffr_lock_all(&mut self.flash_config) })?;
428 Ok(())
429 }
430}