ds_rom/rom/raw/
overlay.rs1use std::{
2 fmt::Display,
3 mem::{align_of, size_of},
4};
5
6use bitfield_struct::bitfield;
7use bytemuck::{Pod, PodCastError, Zeroable};
8use snafu::{Backtrace, Snafu};
9
10use super::RawHeaderError;
11
12#[repr(C)]
14#[derive(Clone, Copy, Zeroable, Pod)]
15pub struct Overlay {
16 pub id: u32,
18 pub base_addr: u32,
20 pub code_size: u32,
22 pub bss_size: u32,
24 pub ctor_start: u32,
26 pub ctor_end: u32,
28 pub file_id: u32,
30 pub compressed: OverlayCompressedSize,
32}
33
34#[derive(Snafu, Debug)]
36pub enum RawOverlayError {
37 #[snafu(transparent)]
39 RawHeader {
40 source: RawHeaderError,
42 },
43 #[snafu(display("the overlay table must be a multiple of {} bytes:\n{backtrace}", size_of::<Overlay>()))]
45 InvalidSize {
46 backtrace: Backtrace,
48 },
49 #[snafu(display("expected {expected}-alignment for overlay table but got {actual}-alignment:\n{backtrace}"))]
51 Misaligned {
52 expected: usize,
54 actual: usize,
56 backtrace: Backtrace,
58 },
59}
60
61impl Overlay {
62 fn check_size(data: &[u8]) -> Result<(), RawOverlayError> {
63 let size = size_of::<Self>();
64 if data.len() % size != 0 {
65 InvalidSizeSnafu {}.fail()
66 } else {
67 Ok(())
68 }
69 }
70
71 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawOverlayError> {
72 match result {
73 Ok(build_info) => Ok(build_info),
74 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
75 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
76 }
77 Err(PodCastError::AlignmentMismatch) => panic!(),
78 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
79 Err(PodCastError::SizeMismatch) => unreachable!(),
80 }
81 }
82
83 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawOverlayError> {
89 Self::check_size(data)?;
90 let addr = data as *const [u8] as *const () as usize;
91 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
92 }
93
94 pub fn display(&self, indent: usize) -> DisplayOverlay {
96 DisplayOverlay { overlay: self, indent }
97 }
98}
99
100pub struct DisplayOverlay<'a> {
102 overlay: &'a Overlay,
103 indent: usize,
104}
105
106impl Display for DisplayOverlay<'_> {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 let i = format!("{:indent$}", "", indent = self.indent);
109 let overlay = &self.overlay;
110 writeln!(f, "{i}ID ............... : {}", overlay.id)?;
111 writeln!(f, "{i}File ID .......... : {}", overlay.file_id)?;
112 writeln!(f, "{i}Base address ..... : {:#x}", overlay.base_addr)?;
113 writeln!(f, "{i}Code size ........ : {:#x}", overlay.code_size)?;
114 writeln!(f, "{i}.bss size ........ : {:#x}", overlay.bss_size)?;
115 writeln!(f, "{i}.ctor start ...... : {:#x}", overlay.ctor_start)?;
116 writeln!(f, "{i}.ctor end ........ : {:#x}", overlay.ctor_end)?;
117 writeln!(f, "{i}Compressed size .. : {:#x}", overlay.compressed.size())?;
118 writeln!(f, "{i}Is compressed .... : {}", overlay.compressed.is_compressed() != 0)?;
119 Ok(())
120 }
121}
122
123#[bitfield(u32)]
125pub struct OverlayCompressedSize {
126 #[bits(24)]
128 pub size: usize,
129 pub is_compressed: u8,
130}
131
132unsafe impl Zeroable for OverlayCompressedSize {}
133unsafe impl Pod for OverlayCompressedSize {}