ds_rom/rom/raw/
multiboot_signature.rs1use std::{backtrace::Backtrace, fmt::Display};
2
3use bytemuck::{Pod, PodCastError, Zeroable};
4use serde::{Deserialize, Serialize};
5use snafu::Snafu;
6
7use crate::{crypto::rsa::RsaSignature, rom::raw::RawHeaderError};
8
9#[repr(C)]
12#[derive(Zeroable, Pod, Clone, Copy, Serialize, Deserialize)]
13pub struct MultibootSignature {
14 magic: u32,
15 rsa_signature: RsaSignature,
16 key_seed: u32,
17}
18
19pub const MULTIBOOT_SIGNATURE_MAGIC: u32 = 0x00016361;
21
22#[derive(Debug, Snafu)]
24pub enum RawMultibootSignatureError {
25 #[snafu(transparent)]
27 RawHeader {
28 source: RawHeaderError,
30 },
31 #[snafu(display("expected {expected:#x} bytes for multiboot signature but had only {actual:#x}:\n{backtrace}"))]
33 DataTooSmall {
34 expected: usize,
36 actual: usize,
38 backtrace: Backtrace,
40 },
41 #[snafu(display("expected {expected}-alignment but got {actual}-alignment:\n{backtrace}"))]
43 Misaligned {
44 expected: usize,
46 actual: usize,
48 backtrace: Backtrace,
50 },
51 #[snafu(display("expected magic number {expected:#010x} but got {actual:#010x}:\n{backtrace}"))]
53 InvalidMagic {
54 expected: u32,
56 actual: u32,
58 backtrace: Backtrace,
60 },
61}
62
63impl MultibootSignature {
64 fn check_size(data: &'_ [u8]) -> Result<(), RawMultibootSignatureError> {
65 let size = size_of::<Self>();
66 if data.len() < size {
67 DataTooSmallSnafu { expected: size, actual: data.len() }.fail()
68 } else {
69 Ok(())
70 }
71 }
72
73 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawMultibootSignatureError> {
74 match result {
75 Ok(build_info) => Ok(build_info),
76 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
77 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
78 }
79 Err(PodCastError::AlignmentMismatch) => panic!(),
80 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
81 Err(PodCastError::SizeMismatch) => unreachable!(),
82 }
83 }
84
85 pub fn borrow_from_slice(data: &[u8]) -> Result<&Self, RawMultibootSignatureError> {
91 let size = size_of::<Self>();
92 Self::check_size(data)?;
93 let addr = data as *const [u8] as *const () as usize;
94 let multiboot_signature: &Self = Self::handle_pod_cast(bytemuck::try_from_bytes(&data[..size]), addr)?;
95 if multiboot_signature.magic != MULTIBOOT_SIGNATURE_MAGIC {
96 return InvalidMagicSnafu { expected: MULTIBOOT_SIGNATURE_MAGIC, actual: multiboot_signature.magic }.fail();
97 }
98 Ok(multiboot_signature)
99 }
100
101 pub fn display(&self, indent: usize) -> DisplayMultibootSignature<'_> {
103 DisplayMultibootSignature { multiboot_signature: self, indent }
104 }
105
106 pub fn magic(&self) -> u32 {
108 self.magic
109 }
110
111 pub fn rsa_signature(&self) -> &RsaSignature {
113 &self.rsa_signature
114 }
115
116 pub fn key_seed(&self) -> u32 {
118 self.key_seed
119 }
120}
121
122pub struct DisplayMultibootSignature<'a> {
124 multiboot_signature: &'a MultibootSignature,
125 indent: usize,
126}
127
128impl Display for DisplayMultibootSignature<'_> {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 let i = " ".repeat(self.indent);
131 let multiboot_signature = &self.multiboot_signature;
132 writeln!(f, "{i}Magic number ... : {:#010x}", multiboot_signature.magic)?;
133 writeln!(f, "{i}RSA key seed ... : {:#010x}", multiboot_signature.key_seed)?;
134 writeln!(f, "{i}RSA signature .. :\n{}", multiboot_signature.rsa_signature.display(self.indent + 2))?;
135 Ok(())
136 }
137}