ds_rom/rom/raw/
overlay.rs1use 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#[repr(C)]
15#[derive(Clone, Copy, Zeroable, Pod)]
16pub struct Overlay {
17 pub id: u32,
19 pub base_addr: u32,
21 pub code_size: u32,
23 pub bss_size: u32,
25 pub ctor_start: u32,
27 pub ctor_end: u32,
29 pub file_id: u32,
31 pub compressed: OverlayCompressedSize,
33}
34
35#[derive(Snafu, Debug)]
37pub enum RawOverlayError {
38 #[snafu(transparent)]
40 RawHeader {
41 source: RawHeaderError,
43 },
44 #[snafu(display("the overlay table must be a multiple of {} bytes:\n{backtrace}", size_of::<Overlay>()))]
46 InvalidSize {
47 backtrace: Backtrace,
49 },
50 #[snafu(display("expected {expected}-alignment for overlay table but got {actual}-alignment:\n{backtrace}"))]
52 Misaligned {
53 expected: usize,
55 actual: usize,
57 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 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 pub fn display(&self, indent: usize) -> DisplayOverlay {
97 DisplayOverlay { overlay: self, indent }
98 }
99}
100
101pub 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#[bitfield(u32)]
126pub struct OverlayCompressedSize {
127 #[bits(24)]
129 pub size: usize,
130 pub is_compressed: u8,
131}
132
133unsafe impl Zeroable for OverlayCompressedSize {}
134unsafe impl Pod for OverlayCompressedSize {}