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 crate::rom::Arm9OverlaySignaturesError;
11
12use super::{RawArm9Error, RawHeaderError};
13
14#[repr(C)]
16#[derive(Clone, Copy, Zeroable, Pod)]
17pub struct Overlay {
18 pub id: u32,
20 pub base_addr: u32,
22 pub code_size: u32,
24 pub bss_size: u32,
26 pub ctor_start: u32,
28 pub ctor_end: u32,
30 pub file_id: u32,
32 pub flags: OverlayFlags,
34}
35
36#[derive(Snafu, Debug)]
38pub enum RawOverlayError {
39 #[snafu(transparent)]
41 RawHeader {
42 source: RawHeaderError,
44 },
45 #[snafu(transparent)]
47 RawArm9 {
48 source: RawArm9Error,
50 },
51 #[snafu(transparent)]
53 Arm9OverlaySignatures {
54 source: Arm9OverlaySignaturesError,
56 },
57 #[snafu(display("the overlay table must be a multiple of {} bytes:\n{backtrace}", size_of::<Overlay>()))]
59 InvalidSize {
60 backtrace: Backtrace,
62 },
63 #[snafu(display("expected {expected}-alignment for overlay table but got {actual}-alignment:\n{backtrace}"))]
65 Misaligned {
66 expected: usize,
68 actual: usize,
70 backtrace: Backtrace,
72 },
73}
74
75impl Overlay {
76 fn check_size(data: &[u8]) -> Result<(), RawOverlayError> {
77 let size = size_of::<Self>();
78 if data.len() % size != 0 {
79 InvalidSizeSnafu {}.fail()
80 } else {
81 Ok(())
82 }
83 }
84
85 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawOverlayError> {
86 match result {
87 Ok(build_info) => Ok(build_info),
88 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
89 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
90 }
91 Err(PodCastError::AlignmentMismatch) => panic!(),
92 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
93 Err(PodCastError::SizeMismatch) => unreachable!(),
94 }
95 }
96
97 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawOverlayError> {
103 Self::check_size(data)?;
104 let addr = data as *const [u8] as *const () as usize;
105 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
106 }
107
108 pub fn display(&self, indent: usize) -> DisplayOverlay {
110 DisplayOverlay { overlay: self, indent }
111 }
112}
113
114pub struct DisplayOverlay<'a> {
116 overlay: &'a Overlay,
117 indent: usize,
118}
119
120impl Display for DisplayOverlay<'_> {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 let i = " ".repeat(self.indent);
123 let overlay = &self.overlay;
124 writeln!(f, "{i}ID ............... : {}", overlay.id)?;
125 writeln!(f, "{i}File ID .......... : {}", overlay.file_id)?;
126 writeln!(f, "{i}Base address ..... : {:#x}", overlay.base_addr)?;
127 writeln!(f, "{i}Code size ........ : {:#x}", overlay.code_size)?;
128 writeln!(f, "{i}.bss size ........ : {:#x}", overlay.bss_size)?;
129 writeln!(f, "{i}.ctor start ...... : {:#x}", overlay.ctor_start)?;
130 writeln!(f, "{i}.ctor end ........ : {:#x}", overlay.ctor_end)?;
131 writeln!(f, "{i}Compressed size .. : {:#x}", overlay.flags.size())?;
132 writeln!(f, "{i}Is compressed .... : {}", overlay.flags.is_compressed())?;
133 writeln!(f, "{i}Is signed ........ : {}", overlay.flags.is_signed())?;
134 writeln!(f, "{i}Reserved flags ... : {:#x}", overlay.flags.reserved())?;
135 Ok(())
136 }
137}
138
139#[bitfield(u32)]
141pub struct OverlayFlags {
142 #[bits(24)]
144 pub size: usize,
145 pub is_compressed: bool,
146 pub is_signed: bool,
147 #[bits(6)]
148 pub reserved: u8,
149}
150
151unsafe impl Zeroable for OverlayFlags {}
152unsafe impl Pod for OverlayFlags {}