1use std::{
2 cmp::Ordering,
3 fmt::Display,
4 mem::{align_of, size_of},
5};
6
7use bytemuck::{Pod, PodCastError, Zeroable};
8use serde::{Deserialize, Serialize};
9use snafu::{Backtrace, Snafu};
10
11use super::RawBuildInfoError;
12
13#[repr(C)]
15#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Zeroable, Pod, Deserialize, Serialize)]
16pub struct AutoloadInfoEntry {
17 pub base_address: u32,
19 pub code_size: u32,
21 pub bss_size: u32,
23}
24
25#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize, Serialize)]
27pub enum AutoloadKind {
28 Itcm,
30 Dtcm,
32 Unknown(u32),
34}
35
36impl PartialOrd for AutoloadKind {
37 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
38 Some(self.cmp(other))
39 }
40}
41
42impl Ord for AutoloadKind {
43 fn cmp(&self, other: &Self) -> Ordering {
44 match (self, other) {
46 (_, _) if self == other => Ordering::Equal,
47 (AutoloadKind::Itcm, _) => Ordering::Less,
48 (_, AutoloadKind::Itcm) => Ordering::Greater,
49 (AutoloadKind::Dtcm, _) => Ordering::Less,
50 (_, AutoloadKind::Dtcm) => Ordering::Greater,
51 (AutoloadKind::Unknown(a), AutoloadKind::Unknown(b)) => a.cmp(b),
52 }
53 }
54}
55
56#[derive(Clone, Copy, Deserialize, Serialize, Debug, PartialEq, Eq)]
58pub struct AutoloadInfo {
59 #[serde(flatten)]
60 pub list_entry: AutoloadInfoEntry,
62 pub kind: AutoloadKind,
64}
65
66#[derive(Debug, Snafu)]
68pub enum RawAutoloadInfoError {
69 #[snafu(transparent)]
71 RawBuildInfo {
72 source: RawBuildInfoError,
74 },
75 #[snafu(display("autoload infos must be a multiple of {} bytes:\n{backtrace}", size_of::<AutoloadInfo>()))]
77 InvalidSize {
78 backtrace: Backtrace,
80 },
81 #[snafu(display("expected {expected}-alignment for autoload infos but got {actual}-alignment:\n{backtrace}"))]
83 Misaligned {
84 expected: usize,
86 actual: usize,
88 backtrace: Backtrace,
90 },
91}
92
93impl AutoloadInfoEntry {
94 fn check_size(data: &'_ [u8]) -> Result<(), RawAutoloadInfoError> {
95 let size = size_of::<Self>();
96 if !data.len().is_multiple_of(size) {
97 InvalidSizeSnafu {}.fail()
98 } else {
99 Ok(())
100 }
101 }
102
103 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawAutoloadInfoError> {
104 match result {
105 Ok(build_info) => Ok(build_info),
106 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
107 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
108 }
109 Err(PodCastError::AlignmentMismatch) => panic!(),
110 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
111 Err(PodCastError::SizeMismatch) => unreachable!(),
112 }
113 }
114
115 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawAutoloadInfoError> {
121 Self::check_size(data)?;
122 let addr = data as *const [u8] as *const () as usize;
123 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
124 }
125}
126
127impl AutoloadInfo {
128 pub fn new(list_entry: AutoloadInfoEntry, index: u32) -> Self {
130 let kind = match list_entry.base_address {
131 0x1ff8000 => AutoloadKind::Itcm,
132 0x27e0000 | 0x27c0000 | 0x23c0000 => AutoloadKind::Dtcm,
133 _ => AutoloadKind::Unknown(index),
134 };
135
136 Self { list_entry, kind }
137 }
138
139 pub fn base_address(&self) -> u32 {
141 self.list_entry.base_address
142 }
143
144 pub fn code_size(&self) -> u32 {
146 self.list_entry.code_size
147 }
148
149 pub fn bss_size(&self) -> u32 {
151 self.list_entry.bss_size
152 }
153
154 pub fn kind(&self) -> AutoloadKind {
156 self.kind
157 }
158
159 pub fn entry(&self) -> &AutoloadInfoEntry {
161 &self.list_entry
162 }
163
164 pub fn display(&self, indent: usize) -> DisplayAutoloadInfo<'_> {
166 DisplayAutoloadInfo { info: self, indent }
167 }
168}
169
170pub struct DisplayAutoloadInfo<'a> {
172 info: &'a AutoloadInfo,
173 indent: usize,
174}
175
176impl Display for DisplayAutoloadInfo<'_> {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 let i = " ".repeat(self.indent);
179 let info = &self.info;
180 writeln!(f, "{i}Type .......... : {}", info.kind)?;
181 writeln!(f, "{i}Base address .. : {:#x}", info.list_entry.base_address)?;
182 writeln!(f, "{i}Code size ..... : {:#x}", info.list_entry.code_size)?;
183 writeln!(f, "{i}.bss size ..... : {:#x}", info.list_entry.bss_size)?;
184 Ok(())
185 }
186}
187
188impl Display for AutoloadKind {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 match self {
191 AutoloadKind::Itcm => write!(f, "ITCM"),
192 AutoloadKind::Dtcm => write!(f, "DTCM"),
193 AutoloadKind::Unknown(index) => write!(f, "Unknown({index})"),
194 }
195 }
196}