ds_rom/rom/raw/
autoload_info.rs1use std::{
2 fmt::Display,
3 mem::{align_of, size_of},
4};
5
6use bytemuck::{Pod, PodCastError, Zeroable};
7use serde::{Deserialize, Serialize};
8use snafu::{Backtrace, Snafu};
9
10use super::RawBuildInfoError;
11
12#[repr(C)]
14#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Zeroable, Pod, Deserialize, Serialize)]
15pub struct AutoloadInfo {
16 pub base_address: u32,
18 pub code_size: u32,
20 pub bss_size: u32,
22}
23
24#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
26pub enum AutoloadKind {
27 Itcm,
29 Dtcm,
31 Unknown(AutoloadInfo),
33}
34
35#[derive(Debug, Snafu)]
37pub enum RawAutoloadInfoError {
38 #[snafu(transparent)]
40 RawBuildInfo {
41 source: RawBuildInfoError,
43 },
44 #[snafu(display("autoload infos must be a multiple of {} bytes:\n{backtrace}", size_of::<AutoloadInfo>()))]
46 InvalidSize {
47 backtrace: Backtrace,
49 },
50 #[snafu(display("expected {expected}-alignment for autoload infos but got {actual}-alignment:\n{backtrace}"))]
52 Misaligned {
53 expected: usize,
55 actual: usize,
57 backtrace: Backtrace,
59 },
60}
61
62impl AutoloadInfo {
63 fn check_size(data: &'_ [u8]) -> Result<(), RawAutoloadInfoError> {
64 let size = size_of::<Self>();
65 if data.len() % size != 0 {
66 InvalidSizeSnafu {}.fail()
67 } else {
68 Ok(())
69 }
70 }
71
72 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawAutoloadInfoError> {
73 match result {
74 Ok(build_info) => Ok(build_info),
75 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
76 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
77 }
78 Err(PodCastError::AlignmentMismatch) => panic!(),
79 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
80 Err(PodCastError::SizeMismatch) => unreachable!(),
81 }
82 }
83
84 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawAutoloadInfoError> {
90 Self::check_size(data)?;
91 let addr = data as *const [u8] as *const () as usize;
92 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
93 }
94
95 pub fn kind(&self) -> AutoloadKind {
97 match self.base_address {
98 0x1ff8000 => AutoloadKind::Itcm,
99 0x27e0000 | 0x27c0000 | 0x23c0000 => AutoloadKind::Dtcm,
100 _ => AutoloadKind::Unknown(*self),
101 }
102 }
103
104 pub fn display(&self, indent: usize) -> DisplayAutoloadInfo {
106 DisplayAutoloadInfo { info: self, indent }
107 }
108}
109
110pub struct DisplayAutoloadInfo<'a> {
112 info: &'a AutoloadInfo,
113 indent: usize,
114}
115
116impl<'a> Display for DisplayAutoloadInfo<'a> {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 let i = format!("{:indent$}", "", indent = self.indent);
119 let info = &self.info;
120 writeln!(f, "{i}Type .......... : {}", info.kind())?;
121 writeln!(f, "{i}Base address .. : {:#x}", info.base_address)?;
122 writeln!(f, "{i}Code size ..... : {:#x}", info.code_size)?;
123 writeln!(f, "{i}.bss size ..... : {:#x}", info.bss_size)?;
124 Ok(())
125 }
126}
127
128impl Display for AutoloadKind {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 match self {
131 AutoloadKind::Itcm => write!(f, "ITCM"),
132 AutoloadKind::Dtcm => write!(f, "DTCM"),
133 AutoloadKind::Unknown(_) => write!(f, "Unknown"),
134 }
135 }
136}