ds_rom/rom/raw/
overlay.rs

1use std::{
2    fmt::Display,
3    mem::{align_of, size_of},
4    usize,
5};
6
7use bitfield_struct::bitfield;
8use bytemuck::{Pod, PodCastError, Zeroable};
9use snafu::{Backtrace, Snafu};
10
11use super::RawHeaderError;
12
13/// An entry in an overlay table. This is the raw struct, see the plain one [here](super::super::Overlay).
14#[repr(C)]
15#[derive(Clone, Copy, Zeroable, Pod)]
16pub struct Overlay {
17    /// Overlay ID.
18    pub id: u32,
19    /// Base address.
20    pub base_addr: u32,
21    /// Initialized size.
22    pub code_size: u32,
23    /// Uninitialized size.
24    pub bss_size: u32,
25    /// Offset to start of .ctor section.
26    pub ctor_start: u32,
27    /// Offset to end of .ctor section.
28    pub ctor_end: u32,
29    /// File ID for the FAT.
30    pub file_id: u32,
31    /// Compressed size.
32    pub compressed: OverlayCompressedSize,
33}
34
35/// Errors related to [`Overlay`].
36#[derive(Snafu, Debug)]
37pub enum RawOverlayError {
38    /// See [`RawHeaderError`].
39    #[snafu(transparent)]
40    RawHeader {
41        /// Source error.
42        source: RawHeaderError,
43    },
44    /// Occurs when the input is not evenly divisible into a slice of [`Overlay`].
45    #[snafu(display("the overlay table must be a multiple of {} bytes:\n{backtrace}", size_of::<Overlay>()))]
46    InvalidSize {
47        /// Backtrace to the source of the error.
48        backtrace: Backtrace,
49    },
50    /// Occurs when the input is less aligned than [`Overlay`].
51    #[snafu(display("expected {expected}-alignment for overlay table but got {actual}-alignment:\n{backtrace}"))]
52    Misaligned {
53        /// Expected alignment.
54        expected: usize,
55        /// Actual input alignment.
56        actual: usize,
57        /// Backtrace to the source of the error.
58        backtrace: Backtrace,
59    },
60}
61
62impl Overlay {
63    fn check_size(data: &[u8]) -> Result<(), RawOverlayError> {
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, RawOverlayError> {
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    /// Reinterprets a `&[u8]` as a reference to [`Overlay`].
85    ///
86    /// # Errors
87    ///
88    /// This function will return an error if the input is the wrong size, or not aligned enough.
89    pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawOverlayError> {
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    /// Creates a [`DisplayOverlay`] which implements [`Display`].
96    pub fn display(&self, indent: usize) -> DisplayOverlay {
97        DisplayOverlay { overlay: self, indent }
98    }
99}
100
101/// Can be used to display values in [`Overlay`].
102pub struct DisplayOverlay<'a> {
103    overlay: &'a Overlay,
104    indent: usize,
105}
106
107impl<'a> Display for DisplayOverlay<'a> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        let i = format!("{:indent$}", "", indent = self.indent);
110        let overlay = &self.overlay;
111        writeln!(f, "{i}ID ............... : {}", overlay.id)?;
112        writeln!(f, "{i}File ID .......... : {}", overlay.file_id)?;
113        writeln!(f, "{i}Base address ..... : {:#x}", overlay.base_addr)?;
114        writeln!(f, "{i}Code size ........ : {:#x}", overlay.code_size)?;
115        writeln!(f, "{i}.bss size ........ : {:#x}", overlay.bss_size)?;
116        writeln!(f, "{i}.ctor start ...... : {:#x}", overlay.ctor_start)?;
117        writeln!(f, "{i}.ctor end ........ : {:#x}", overlay.ctor_end)?;
118        writeln!(f, "{i}Compressed size .. : {:#x}", overlay.compressed.size())?;
119        writeln!(f, "{i}Is compressed .... : {}", overlay.compressed.is_compressed() != 0)?;
120        Ok(())
121    }
122}
123
124/// Overlay compressed size bitfield.
125#[bitfield(u32)]
126pub struct OverlayCompressedSize {
127    /// Compressed size, zero if not compressed.
128    #[bits(24)]
129    pub size: usize,
130    pub is_compressed: u8,
131}
132
133unsafe impl Zeroable for OverlayCompressedSize {}
134unsafe impl Pod for OverlayCompressedSize {}