ds_rom/rom/raw/
overlay.rs

1use 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/// An entry in an overlay table. This is the raw struct, see the plain one [here](super::super::Overlay).
13#[repr(C)]
14#[derive(Clone, Copy, Zeroable, Pod)]
15pub struct Overlay {
16    /// Overlay ID.
17    pub id: u32,
18    /// Base address.
19    pub base_addr: u32,
20    /// Initialized size.
21    pub code_size: u32,
22    /// Uninitialized size.
23    pub bss_size: u32,
24    /// Offset to start of .ctor section.
25    pub ctor_start: u32,
26    /// Offset to end of .ctor section.
27    pub ctor_end: u32,
28    /// File ID for the FAT.
29    pub file_id: u32,
30    /// Compressed size.
31    pub compressed: OverlayCompressedSize,
32}
33
34/// Errors related to [`Overlay`].
35#[derive(Snafu, Debug)]
36pub enum RawOverlayError {
37    /// See [`RawHeaderError`].
38    #[snafu(transparent)]
39    RawHeader {
40        /// Source error.
41        source: RawHeaderError,
42    },
43    /// Occurs when the input is not evenly divisible into a slice of [`Overlay`].
44    #[snafu(display("the overlay table must be a multiple of {} bytes:\n{backtrace}", size_of::<Overlay>()))]
45    InvalidSize {
46        /// Backtrace to the source of the error.
47        backtrace: Backtrace,
48    },
49    /// Occurs when the input is less aligned than [`Overlay`].
50    #[snafu(display("expected {expected}-alignment for overlay table but got {actual}-alignment:\n{backtrace}"))]
51    Misaligned {
52        /// Expected alignment.
53        expected: usize,
54        /// Actual input alignment.
55        actual: usize,
56        /// Backtrace to the source of the error.
57        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    /// Reinterprets a `&[u8]` as a reference to [`Overlay`].
84    ///
85    /// # Errors
86    ///
87    /// This function will return an error if the input is the wrong size, or not aligned enough.
88    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    /// Creates a [`DisplayOverlay`] which implements [`Display`].
95    pub fn display(&self, indent: usize) -> DisplayOverlay {
96        DisplayOverlay { overlay: self, indent }
97    }
98}
99
100/// Can be used to display values in [`Overlay`].
101pub 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/// Overlay compressed size bitfield.
124#[bitfield(u32)]
125pub struct OverlayCompressedSize {
126    /// Compressed size, zero if not compressed.
127    #[bits(24)]
128    pub size: usize,
129    pub is_compressed: u8,
130}
131
132unsafe impl Zeroable for OverlayCompressedSize {}
133unsafe impl Pod for OverlayCompressedSize {}