diff --git a/src/common.rs b/src/common.rs index 3086efd..cf3d587 100644 --- a/src/common.rs +++ b/src/common.rs @@ -27,6 +27,13 @@ pub(crate) const FDT_NOP: u32 = 0x4; pub(crate) const FDT_END: u32 = 0x9; pub(crate) const SUPPORTED_VERSION: u32 = 17; +// In spec 5.6: +// Specifically, the memory reservation block shall +// be aligned to an 8-byte boundary and the structure +// block to a 4-byte boundary. +pub(crate) const OFFSET_ALIGN: u32 = 64; +pub(crate) const HEADER_PADDING_LEN: u32 = HEADER_LEN.div_ceil(OFFSET_ALIGN) * OFFSET_ALIGN; + impl Header { pub fn verify(&self) -> Result<(), Error> { let header_base = self as *const _ as usize; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 3487562..0bc404e 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -19,49 +19,70 @@ where { writer.iter_mut().for_each(|x| *x = 0); - let mut offset: usize = 0; - { - let mut dst = crate::ser::pointer::Pointer::new(None); - let mut patch_list = crate::ser::patch::PatchList::new(list); - let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset); - let mut ser = - crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list); - let ser = crate::ser::serializer::Serializer::new(&mut ser); - data.serialize(ser)?; + let string_block_length = { + let mut offset: usize = 0; + { + let mut dst = crate::ser::pointer::Pointer::new(None); + let mut patch_list = crate::ser::patch::PatchList::new(list); + let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset); + let mut ser = + crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list); + let ser = crate::ser::serializer::Serializer::new(&mut ser); + data.serialize(ser)?; + offset + }; + { + let mut block = crate::ser::string_block::StringBlock::new(writer, &mut offset); + block.align(); + }; + offset }; list.iter().for_each(|patch| patch.init()); // Write from bottom to top, to avoid overlap. - for i in (0..offset).rev() { - writer[writer.len() - offset + i] = writer[i]; + for i in (0..string_block_length).rev() { + writer[writer.len() - string_block_length + i] = writer[i]; writer[i] = 0; } - // TODO: make sure no out of bound. - let writer_len = writer.len(); - let (data_block, string_block) = writer.split_at_mut(writer.len() - offset); - let (header, data_block) = data_block.split_at_mut(HEADER_LEN as usize + RSVMAP_LEN); let struct_len = { + let (data_block, string_block) = writer.split_at_mut(writer.len() - string_block_length); + let (_, data_block) = data_block.split_at_mut(HEADER_PADDING_LEN as usize + RSVMAP_LEN); let mut patch_list = crate::ser::patch::PatchList::new(list); - let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut offset); + let mut temp_length = string_block_length; + let mut block = crate::ser::string_block::StringBlock::new(string_block, &mut temp_length); let mut dst = crate::ser::pointer::Pointer::new(Some(data_block)); let mut ser = crate::ser::serializer::SerializerInner::new(&mut dst, &mut block, &mut patch_list); let ser = crate::ser::serializer::Serializer::new(&mut ser); - data.serialize(ser)? + let struct_len = data.serialize(ser)?.1; + assert_eq!(struct_len % 4, 0); // As spec, structure block align with 4 bytes. + assert_eq!(temp_length, string_block_length); // StringBlock should be same with first run. + struct_len + }; + + // Align to 8-bytes. + for i in 0..string_block_length { + writer[HEADER_PADDING_LEN as usize + RSVMAP_LEN + struct_len + i] = + writer[writer.len() - string_block_length + i]; + writer[writer.len() - string_block_length + i] = 0; } - .1; + // Make header { + let (header, _) = writer.split_at_mut(HEADER_LEN as usize); let header = unsafe { &mut *(header.as_mut_ptr() as *mut Header) }; header.magic = u32::from_be(DEVICE_TREE_MAGIC); - header.total_size = u32::from_be(writer_len as u32); - header.off_dt_struct = u32::from_be(HEADER_LEN + RSVMAP_LEN as u32); - header.off_dt_strings = u32::from_be((writer_len - offset) as u32); - header.off_mem_rsvmap = u32::from_be(HEADER_LEN); + header.total_size = u32::from_be( + HEADER_PADDING_LEN + (RSVMAP_LEN + struct_len + string_block_length) as u32, + ); + assert_eq!(header.total_size % 8, 0); + header.off_dt_struct = u32::from_be(HEADER_PADDING_LEN + RSVMAP_LEN as u32); + header.off_dt_strings = u32::from_be(HEADER_PADDING_LEN + (RSVMAP_LEN + struct_len) as u32); + header.off_mem_rsvmap = u32::from_be(HEADER_PADDING_LEN); header.version = u32::from_be(SUPPORTED_VERSION); header.last_comp_version = u32::from_be(SUPPORTED_VERSION); // TODO: maybe 16 - header.boot_cpuid_phys = 0; // TODO: wtf is this prop - header.size_dt_strings = u32::from_be(offset as u32); + header.boot_cpuid_phys = 0; // TODO + header.size_dt_strings = u32::from_be(string_block_length as u32); header.size_dt_struct = u32::from_be(struct_len as u32); } Ok(()) diff --git a/src/ser/serializer.rs b/src/ser/serializer.rs index 2b982f3..39b03d1 100644 --- a/src/ser/serializer.rs +++ b/src/ser/serializer.rs @@ -535,7 +535,7 @@ impl<'se> serde::ser::Serializer for Serializer<'_, 'se> { #[cfg(test)] mod tests { use serde::Serialize; - const MAX_SIZE: usize = 256 + 32; + const MAX_SIZE: usize = 256 + 128; #[test] fn base_ser_test() { #[derive(Serialize)] diff --git a/src/ser/string_block.rs b/src/ser/string_block.rs index af86434..672b7d3 100644 --- a/src/ser/string_block.rs +++ b/src/ser/string_block.rs @@ -51,6 +51,15 @@ impl<'se> StringBlock<'se> { result } + /// Align string block size to 8 bytes + #[inline(always)] + pub fn align(&mut self) { + while (*self.end & 0b111) != 0 { + self.data[*self.end] = 0; + *self.end += 1; + } + } + /// Find a string. If not found, insert it. #[inline(always)] pub fn find_or_insert(&mut self, name: &str) -> usize {