diff --git a/src/efs.rs b/src/efs.rs index 78ba14f..0fac34f 100644 --- a/src/efs.rs +++ b/src/efs.rs @@ -1,16 +1,16 @@ use crate::amdfletcher32::AmdFletcher32; use crate::ondisk::header_from_collection; use crate::ondisk::header_from_collection_mut; +use crate::ondisk::DirectoryEntrySerde; pub use crate::ondisk::ProcessorGeneration; use crate::ondisk::EFH_POSITION; use crate::ondisk::{ mmio_decode, mmio_encode, AddressMode, BhdDirectoryEntry, - BhdDirectoryEntryType, BhdDirectoryHeader, - DirectoryAdditionalInfo, DirectoryEntry, DirectoryHeader, Efh, - PspDirectoryEntry, PspDirectoryEntryType, - PspDirectoryHeader, EfhRomeSpiMode, EfhNaplesSpiMode, EfhBulldozerSpiMode, - ComboDirectoryHeader, ComboDirectoryEntry, ValueOrLocation, - WEAK_ADDRESS_MODE, + BhdDirectoryEntryType, BhdDirectoryHeader, ComboDirectoryEntry, + ComboDirectoryHeader, DirectoryAdditionalInfo, DirectoryEntry, + DirectoryHeader, Efh, EfhBulldozerSpiMode, EfhNaplesSpiMode, + EfhRomeSpiMode, PspDirectoryEntry, PspDirectoryEntryType, + PspDirectoryHeader, ValueOrLocation, WEAK_ADDRESS_MODE, }; use crate::types::Error; use crate::types::Result; @@ -21,7 +21,6 @@ use core::marker::PhantomData; use core::mem::size_of; use zerocopy::AsBytes; use zerocopy::FromBytes; -use crate::ondisk::DirectoryEntrySerde; pub struct DirectoryIter< 'a, @@ -52,8 +51,10 @@ impl< [0xff; ERASABLE_BLOCK_SIZE]; let buf = &mut buf[.. size_of::()]; self.storage.read_exact(self.current, buf).ok()?; - let result = Item::from_bytes_b(buf)?; // TODO: Check for errors. - self.current = self.current.checked_add(size_of::() as u32)?; + let result = Item::from_slice(buf)?; // TODO: Check for errors. + self.current = self + .current + .checked_add(size_of::() as u32)?; self.index += 1; let q = result; Some(q) @@ -63,52 +64,6 @@ impl< } } -pub trait DirectoryFrontend { - fn add_blob_entry( - &mut self, - payload_position: Option>, - entry: &mut Item, - iterative_contents: &mut dyn FnMut(&mut [u8]) -> Result - ) -> Result>; - - // - // The comment in efs.rs:add_payload() states that the function passed into - // directory.add_blob_entry() must not return a result smaller than the length - // of the buffer passed into it unless there are no more contents. This means - // we cannot expect it to be called repeatedly, which is to say that we must - // loop ourselves until the reader we are given returns no more data. This - // matters because it is *not* an error for a reader to return less data than - // would have filled the buffer it was given, even if more data might be - // available. - // - #[cfg(feature = "std")] - fn add_from_reader_with_custom_size( - &mut self, - payload_position: Option>, - entry: &mut Item, - source: &mut Source, - ) -> Result<()> - { - self.add_blob_entry( - payload_position, - entry, - &mut |buf: &mut [u8]| { - let mut cursor = 0; - loop { - let bytes = source - .read(&mut buf[cursor ..]) - .map_err(|_| Error::Marshal)?; - if bytes == 0 { - return Ok(cursor); - } - cursor += bytes; - } - }, - )?; - Ok(()) - } -} - // TODO: split into Directory and DirectoryContents (disjunct) if requested in additional_info. pub struct Directory< 'a, @@ -117,7 +72,7 @@ pub struct Directory< T: FlashRead + FlashWrite, const _SPI_BLOCK_SIZE: usize, const ERASABLE_BLOCK_SIZE: usize, - const MainHeaderSize: usize, + const MAIN_HEADER_SIZE: usize, > { storage: &'a T, location: Location, // ideally ErasableLocation--but that's impossible with AMD-generated images. @@ -141,9 +96,17 @@ impl< + FlashWrite, const SPI_BLOCK_SIZE: usize, const ERASABLE_BLOCK_SIZE: usize, - const MainHeaderSize: usize, + const MAIN_HEADER_SIZE: usize, + > + Directory< + 'a, + MainHeader, + Item, + T, + SPI_BLOCK_SIZE, + ERASABLE_BLOCK_SIZE, + MAIN_HEADER_SIZE, > - Directory<'a, MainHeader, Item, T, SPI_BLOCK_SIZE, ERASABLE_BLOCK_SIZE, MainHeaderSize> { const SPI_BLOCK_SIZE: usize = SPI_BLOCK_SIZE; const MAX_DIRECTORY_HEADERS_SIZE: u32 = SPI_BLOCK_SIZE as u32; // AMD says 0x400; but then good luck with modifying the first entry payload without clobbering the directory that comes right before it. @@ -159,7 +122,7 @@ impl< } fn minimal_directory_headers_size(total_entries: u32) -> Result { - Ok(size_of::() + size_of::() .checked_add( size_of::() .checked_mul(total_entries as usize) @@ -167,7 +130,7 @@ impl< ) .ok_or(Error::DirectoryRangeCheck)? .try_into() - .map_err(|_| Error::DirectoryRangeCheck)?) + .map_err(|_| Error::DirectoryRangeCheck) } /// Note: Caller has to check whether it is the right cookie (possibly afterwards)! @@ -176,9 +139,8 @@ impl< location: Location, amd_physical_mode_mmio_size: Option, ) -> Result { - let mut buf: [u8; MainHeaderSize] = - [0xff; MainHeaderSize]; - assert!(MainHeaderSize == size_of::()); // TODO: move to compile-time + let mut buf: [u8; MAIN_HEADER_SIZE] = [0xff; MAIN_HEADER_SIZE]; + assert_eq!(MAIN_HEADER_SIZE, size_of::()); // TODO: move to compile-time storage.read_exact(location, &mut buf)?; match header_from_collection::(&buf[..]) { Some(header) => { @@ -191,7 +153,9 @@ impl< header.additional_info().base_address(), ) .unwrap(); - let directory_address_mode = header.additional_info().address_mode(); + let directory_address_mode = header + .additional_info() + .address_mode(); match directory_address_mode { AddressMode::PhysicalAddress | AddressMode::EfsRelativeOffset | AddressMode::DirectoryRelativeOffset => { } @@ -255,16 +219,16 @@ impl< .try_into() .map_err(|_| Error::DirectoryRangeCheck)?, ) - .ok_or_else(|| Error::DirectoryRangeCheck)?, + .ok_or(Error::DirectoryRangeCheck)?, ) .map_err(|_| Error::DirectoryRangeCheck)? .with_spi_block_size_checked( DirectoryAdditionalInfo::try_into_unit( Self::SPI_BLOCK_SIZE, ) - .ok_or_else(|| Error::DirectoryRangeCheck)? - .try_into() - .map_err(|_| Error::DirectoryRangeCheck)?, + .ok_or(Error::DirectoryRangeCheck)? + // .try_into() + // .map_err(|_| Error::DirectoryRangeCheck)?, ) .map_err(|_| Error::DirectoryRangeCheck)? // We put the actual payload at some distance from the directory, but still close-by--in order to be able to grow the directory later (when there's already payload) @@ -272,17 +236,17 @@ impl< DirectoryAdditionalInfo::try_into_unit( (Location::from(beginning) .checked_add(Self::MAX_DIRECTORY_HEADERS_SIZE) - .ok_or_else(|| Error::DirectoryRangeCheck)?) + .ok_or(Error::DirectoryRangeCheck)?) .try_into() .map_err(|_| Error::DirectoryRangeCheck)?, ) - .ok_or_else(|| Error::DirectoryRangeCheck)? - .try_into() - .map_err(|_| Error::DirectoryRangeCheck)?, + .ok_or(Error::DirectoryRangeCheck)? ) .with_address_mode(AddressMode::EfsRelativeOffset); item.set_additional_info(additional_info); - storage.erase_and_write_blocks(beginning, &buf)?; + storage.erase_and_write_blocks( + beginning, &buf, + )?; Self::load( storage, Location::from(beginning), @@ -298,8 +262,7 @@ impl< let old_total_entries = self.header.total_entries(); let flash_input_block_size = Self::minimal_directory_headers_size(total_entries)?; - let mut flash_input_block_address: Location = - self.location.into(); + let mut flash_input_block_address = self.location; let mut buf = [0xFFu8; ERASABLE_BLOCK_SIZE]; let mut flash_input_block_remainder = flash_input_block_size; let mut checksummer = AmdFletcher32::new(); @@ -319,7 +282,7 @@ impl< if count > flash_input_block_remainder { count = flash_input_block_remainder; } - assert!(count % 2 == 0); + assert_eq!(count % 2, 0); assert!(count as usize >= skip); let block = &buf[skip .. count as usize].chunks(2).map( |bytes| { @@ -373,14 +336,14 @@ impl< } } fn directory_beginning(&self) -> Location { - let location: Location = self.location.into(); + let location = self.location; location + size_of::() as Location // FIXME: range check } /// This will return whatever space is allocated--whether it's in use or not! fn directory_end(&self) -> Location { let headers_size = self.directory_headers_size; assert!((headers_size as usize) >= size_of::()); - let location: Location = self.location.into(); + let location: Location = self.location; // Note: should be erasable (but we don't care on this side; on the other hand, see contents_beginning) location + headers_size // FIXME: range check } @@ -391,7 +354,7 @@ impl< ) .unwrap(); if contents_base == 0 { - self.directory_end().try_into().unwrap() + self.directory_end() } else { let base: u32 = contents_base.try_into().unwrap(); base @@ -406,7 +369,7 @@ impl< .unwrap() .try_into() .unwrap(); - let location = Location::from(self.contents_beginning()); + let location = self.contents_beginning(); // Assumption: SIZE includes the size of the main directory header. // FIXME: What happens in the case contents_base != 0 ? I think then it doesn't include it. let end = location + size - self.directory_headers_size; // FIXME: range check @@ -424,45 +387,58 @@ impl< } } - pub fn location_of_source(&self, source: ValueOrLocation, entry_base_location: Location) -> Result { + pub fn location_of_source( + &self, + source: ValueOrLocation, + entry_base_location: Location, + ) -> Result { match source { ValueOrLocation::Value(_) => { Err(Error::DirectoryTypeMismatch) } - ValueOrLocation::PhysicalAddress(y) => { // or unknown - if let Some(amd_physical_mode_mmio_size) = self.amd_physical_mode_mmio_size { - match mmio_decode(y, amd_physical_mode_mmio_size) { - Ok(x) => Ok(x), - Err(_) => { - // Older Zen models also allowed a flash offset here. - // So allow that as well. - // TODO: Maybe thread through the processor - // generation and only do on Naples. - if y < amd_physical_mode_mmio_size { + ValueOrLocation::PhysicalAddress(y) => { + // or unknown + self.amd_physical_mode_mmio_size.map(|size| { + mmio_decode(y, size) + .or_else(|_| + // Older Zen models + // also allowed a + // flash offset here. + // So allow that as + // well. + // TODO: Maybe thread + // through the + // processor + // generation and + // only do on Naples + // and Rome. + if y < size { Ok(y) } else { - return Err(Error::EntryTypeMismatch) + Err(Error::EntryTypeMismatch) } - } - } - } else { - return Err(Error::EntryTypeMismatch) - } - } - ValueOrLocation::EfsRelativeOffset(x) => { - Ok(x) - } - ValueOrLocation::DirectoryRelativeOffset(y) => { - Ok(self.location.checked_add(y).ok_or(Error::DirectoryPayloadRangeCheck)?) - } - ValueOrLocation::EntryRelativeOffset(y) => { - Ok(y.checked_add(entry_base_location).ok_or(Error::DirectoryPayloadRangeCheck)?) + ) + }).ok_or(Error::EntryTypeMismatch)? } + ValueOrLocation::EfsRelativeOffset(x) => Ok(x), + ValueOrLocation::DirectoryRelativeOffset(y) => Ok(self + .location + .checked_add(y) + .ok_or(Error::DirectoryPayloadRangeCheck)?), + ValueOrLocation::EntryRelativeOffset(y) => Ok(y + .checked_add(entry_base_location) + .ok_or(Error::DirectoryPayloadRangeCheck)?), } } - pub fn entry_location(&self, entry: &dyn DirectoryEntry) -> Result { - self.location_of_source(entry.source(self.directory_address_mode)?, 0/*FIXME*/) + pub fn entry_location( + &self, + entry: &dyn DirectoryEntry, + ) -> Result { + self.location_of_source( + entry.source(self.directory_address_mode)?, + 0, /*FIXME*/ + ) } pub(crate) fn find_payload_empty_slot( @@ -470,8 +446,7 @@ impl< size: u32, ) -> Result> { let entries = self.entries(); - let contents_beginning = - Location::from(self.contents_beginning()) as u64; + let contents_beginning = self.contents_beginning() as u64; let contents_end = Location::from(self.contents_end()) as u64; let mut frontier: u64 = contents_beginning; // TODO: Also use gaps between entries @@ -480,22 +455,33 @@ impl< let size = match entry.size() { None => { entry_offset = entry_offset.checked_add(size_of::().try_into().map_err(|_| Error::DirectoryPayloadRangeCheck)?).ok_or(Error::DirectoryPayloadRangeCheck)?; - continue + continue; } Some(x) => x as u64, }; - let x = self.location_of_source(entry.source(self.directory_address_mode)?, self.location.checked_add(entry_offset).ok_or(Error::DirectoryPayloadRangeCheck)? /* FIXME */)?; + let x = self.location_of_source( + entry.source(self.directory_address_mode)?, + self.location.checked_add(entry_offset).ok_or( + Error::DirectoryPayloadRangeCheck, + )?, /* FIXME */ + )?; let x = u64::from(x); - if x >= contents_beginning && - x + size <= contents_end - { + if x >= contents_beginning && x + size <= contents_end { let new_frontier = x + size; // FIXME bounds check if new_frontier > frontier { frontier = new_frontier; } } - entry_offset = entry_offset.checked_add(size_of::().try_into().map_err(|_| Error::DirectoryPayloadRangeCheck)?).ok_or(Error::DirectoryPayloadRangeCheck)?; + entry_offset = entry_offset + .checked_add( + size_of::().try_into().map_err( + |_| { + Error::DirectoryPayloadRangeCheck + }, + )?, + ) + .ok_or(Error::DirectoryPayloadRangeCheck)?; } let frontier: Location = frontier .try_into() @@ -523,11 +509,10 @@ impl< beginning.try_into().map_err(|_| Error::Misaligned)?; self.storage.read_erasable_block(beginning, &mut buf)?; // FIXME: what if this straddles two different blocks? - let destination = &mut buf[buf_index .. buf_index + size_of::()]; + let destination = + &mut buf[buf_index .. buf_index + size_of::()]; entry.copy_into_slice(destination); - self.storage.erase_and_write_blocks( - beginning, &buf, - )?; + self.storage.erase_and_write_blocks(beginning, &buf)?; Ok(()) } /// PAYLOAD_POSITION: If you have a position on the Flash that you want this fn to use, specify it. Otherwise, one will be calculated. @@ -570,10 +555,11 @@ impl< match result { None => {} Some(beginning) => { - let beginning = Location::from(beginning); + let beginning = + Location::from(beginning); entry.set_source(self.directory_address_mode, match self.directory_address_mode { AddressMode::PhysicalAddress => { - ValueOrLocation::PhysicalAddress(mmio_encode(Location::from(beginning).into(), self.amd_physical_mode_mmio_size)?) + ValueOrLocation::PhysicalAddress(mmio_encode(beginning, self.amd_physical_mode_mmio_size)?) }, AddressMode::EfsRelativeOffset => { ValueOrLocation::EfsRelativeOffset(beginning) @@ -588,13 +574,13 @@ impl< })?; } } - let location: Location = self.location.into(); + let location: Location = self.location; self.write_directory_entry( location + Self::minimal_directory_headers_size( self.header.total_entries(), )?, - &entry, + entry, )?; // FIXME check bounds self.update_main_header(total_entries)?; Ok(result) @@ -619,8 +605,7 @@ impl< [0xFF; ERASABLE_BLOCK_SIZE]; let mut remaining_size = size; let mut payload_position = payload_position; - let contents_beginning = - Location::from(self.contents_beginning()); + let contents_beginning = self.contents_beginning(); let contents_end = Location::from(self.contents_end()); let payload_meant_inside_contents = Location::from( payload_position, @@ -669,6 +654,73 @@ impl< } Ok(()) } + + /// Adds ENTRY to the directory. + /// The added entry will have its source fixed up. + pub fn add_blob_entry( + &mut self, + payload_position: Option>, + entry: &mut Item, + iterative_contents: &mut dyn FnMut(&mut [u8]) -> Result, + ) -> Result> { + //let mut entry = *entry; + entry.set_source( + self.directory_address_mode, + ValueOrLocation::EfsRelativeOffset( + payload_position.map_or(0, |x| x.into()) + ), + )?; + let size = entry.size().ok_or(Error::EntryTypeMismatch)?; + let xpayload_position = + self.add_entry(payload_position, entry)?; + match xpayload_position { + None => Err(Error::EntryTypeMismatch), + Some(pos) => { + self.add_payload( + pos, + size as usize, + iterative_contents, + )?; + Ok(pos) + } + } + } + + // + // The comment in efs.rs:add_payload() states that the function passed into + // directory.add_blob_entry() must not return a result smaller than the length + // of the buffer passed into it unless there are no more contents. This means + // we cannot expect it to be called repeatedly, which is to say that we must + // loop ourselves until the reader we are given returns no more data. This + // matters because it is *not* an error for a reader to return less data than + // would have filled the buffer it was given, even if more data might be + // available. + // + #[cfg(feature = "std")] + pub fn add_from_reader_with_custom_size( + &mut self, + payload_position: Option>, + entry: &mut Item, + source: &mut Source, + ) -> Result<()> { + self.add_blob_entry( + payload_position, + entry, + &mut |buf: &mut [u8]| { + let mut cursor = 0; + loop { + let bytes = source + .read(&mut buf[cursor ..]) + .map_err(|_| Error::Marshal)?; + if bytes == 0 { + return Ok(cursor); + } + cursor += bytes; + } + }, + )?; + Ok(()) + } } pub type PspDirectory<'a, T, const ERASABLE_BLOCK_SIZE: usize> = Directory< @@ -727,12 +779,10 @@ impl< // Find existing SecondLevelDirectory, error out if found. let entries = self.entries(); for entry in entries { - match entry.type_or_err() { - Ok(PspDirectoryEntryType::SecondLevelDirectory) => { - return Err(Error::Duplicate); - } - _ => { // maybe just unknown - } + if let Ok(PspDirectoryEntryType::SecondLevelDirectory) = + entry.type_or_err() + { + return Err(Error::Duplicate); } } self.add_entry( @@ -758,72 +808,16 @@ impl< pub fn add_value_entry( &mut self, entry: &mut PspDirectoryEntry, - ) -> Result<()> - { - match entry.source(WEAK_ADDRESS_MODE)? { - ValueOrLocation::Value(_) => { - self.add_entry(None, entry)?; - Ok(()) - } - _ => { - Err(Error::EntryTypeMismatch) - } + ) -> Result<()> { + if let ValueOrLocation::Value(_) = entry.source(WEAK_ADDRESS_MODE)? { + self.add_entry(None, entry)?; + Ok(()) + } else { + Err(Error::EntryTypeMismatch) } } } -impl< - 'a, - T: 'a - + FlashRead - + FlashWrite, - const SPI_BLOCK_SIZE: usize, - const ERASABLE_BLOCK_SIZE: usize, - > -DirectoryFrontend for - Directory< - 'a, - PspDirectoryHeader, - PspDirectoryEntry, - T, - SPI_BLOCK_SIZE, - ERASABLE_BLOCK_SIZE, - { size_of::() }, - > -{ - /// Adds ENTRY to the directory. - /// The added entry will have its source fixed up. - fn add_blob_entry( - &mut self, - payload_position: Option>, - entry: &mut PspDirectoryEntry, - iterative_contents: &mut dyn FnMut(&mut [u8]) -> Result, - ) -> Result> { - entry.set_source(self.directory_address_mode, ValueOrLocation::EfsRelativeOffset( - match payload_position { - None => 0, - Some(x) => x.into(), - } - )); - let size = entry.size().ok_or(Error::EntryTypeMismatch)?; - let xpayload_position = self.add_entry( - payload_position, - entry, - )?; - match xpayload_position { - None => Err(Error::EntryTypeMismatch), - Some(pos) => { - self.add_payload( - pos, - size as usize, - iterative_contents, - )?; - Ok(pos) - } - } - } -} - impl< 'a, T: 'a @@ -851,12 +845,10 @@ impl< // Find existing SecondLevelDirectory, error out if found. let entries = self.entries(); for entry in entries { - match entry.type_or_err() { - Ok(BhdDirectoryEntryType::SecondLevelDirectory) => { - return Err(Error::Duplicate); - } - _ => { // maybe just unknown type. - } + if let Ok(BhdDirectoryEntryType::SecondLevelDirectory) = + entry.type_or_err() + { + return Err(Error::Duplicate); } } self.add_entry( @@ -871,7 +863,7 @@ impl< )?; Self::create( self.directory_address_mode, - &mut self.storage, + self.storage, beginning, end, *b"$BL2", @@ -889,63 +881,13 @@ impl< type_, Some(0), Some(ValueOrLocation::PhysicalAddress(0)), - Some(ram_destination_address) + Some(ram_destination_address), )?; self.add_entry(None, &mut entry)?; Ok(()) } } -impl< - 'a, - T: 'a - + FlashRead - + FlashWrite, - const SPI_BLOCK_SIZE: usize, - const ERASABLE_BLOCK_SIZE: usize, - > -DirectoryFrontend for - Directory< - 'a, - BhdDirectoryHeader, - BhdDirectoryEntry, - T, - SPI_BLOCK_SIZE, - ERASABLE_BLOCK_SIZE, - { size_of::() }, - > -{ - fn add_blob_entry( - &mut self, - payload_position: Option>, - entry: &mut BhdDirectoryEntry, - iterative_contents: &mut dyn FnMut(&mut [u8]) -> Result, - ) -> Result> { - entry.set_source(self.directory_address_mode, ValueOrLocation::EfsRelativeOffset( - match payload_position { - None => 0, - Some(x) => x.into(), - } - )); - let size = entry.size().ok_or(Error::EntryTypeMismatch)?; - let xpayload_position = self.add_entry( - payload_position, - entry, - )?; - match xpayload_position { - None => Err(Error::EntryTypeMismatch), - Some(pos) => { - self.add_payload( - pos, - size as usize, - iterative_contents, - )?; - Ok(pos) - } - } - } -} - pub struct EfhBhdsIterator< 'a, T: FlashRead + FlashWrite, @@ -974,28 +916,25 @@ impl< if position != 0xffff_ffff && position != 0 /* sigh. Some images have 0 as "invalid" mark */ { - match BhdDirectory::load( + return BhdDirectory::load( self.storage, position, self.amd_physical_mode_mmio_size, - ) { - Ok(e) => { - return Some(e); - } - Err(e) => { - return None; // FIXME: error check - } - } + ).ok() // FIXME: error check } } None } } -pub const fn preferred_efh_location(processor_generation: ProcessorGeneration) -> Location { +pub const fn preferred_efh_location( + processor_generation: ProcessorGeneration, +) -> Location { match processor_generation { ProcessorGeneration::Naples => 0x2_0000, - ProcessorGeneration::Rome | ProcessorGeneration::Milan => 0xFA_0000, + ProcessorGeneration::Rome | ProcessorGeneration::Milan => { + 0xFA_0000 + } } } @@ -1028,26 +967,23 @@ impl< let mut xbuf: [u8; ERASABLE_BLOCK_SIZE] = [0; ERASABLE_BLOCK_SIZE]; storage.read_exact(*position, &mut xbuf)?; - match header_from_collection::(&xbuf[..]) { - Some(item) => { - // Note: only one Efh with second_gen_efs() allowed in entire Flash! - if item.signature().ok().or(Some(0)).unwrap() == 0x55AA55AA && - item.second_gen_efs() && - match processor_generation { - Some(x) => item - .compatible_with_processor_generation( - x, - ), - None => true, - } { - return Ok(ErasableLocation::< - ERASABLE_BLOCK_SIZE, - >::try_from( - *position - )?); - } + if let Some(item) = + header_from_collection::(&xbuf[..]) + { + // Note: only one Efh with second_gen_efs() allowed in entire Flash! + if item.signature().ok().unwrap_or(0) == + 0x55AA55AA && item.second_gen_efs() && + match processor_generation { + Some(x) => item + .compatible_with_processor_generation( + x, + ), + None => true, + } { + return Ok(ErasableLocation::< + ERASABLE_BLOCK_SIZE, + >::try_from(*position)?); } - None => {} } } // Old firmware header is better than no firmware header; TODO: Warn. @@ -1055,23 +991,20 @@ impl< let mut xbuf: [u8; ERASABLE_BLOCK_SIZE] = [0; ERASABLE_BLOCK_SIZE]; storage.read_exact(*position, &mut xbuf)?; - match header_from_collection::(&xbuf[..]) { - Some(item) => { - if item.signature().ok().or(Some(0)).unwrap() == 0x55AA55AA && - !item.second_gen_efs() && - match processor_generation { - //Some(x) => item.compatible_with_processor_generation(x), - None => true, - _ => false, - } { - return Ok(ErasableLocation::< - ERASABLE_BLOCK_SIZE, - >::try_from( - *position - )?); - } + if let Some(item) = + header_from_collection::(&xbuf[..]) + { + if item.signature().ok().unwrap_or(0) == + 0x55AA55AA && !item.second_gen_efs() && + match processor_generation { + //Some(x) => item.compatible_with_processor_generation(x), + None => true, + _ => false, + } { + return Ok(ErasableLocation::< + ERASABLE_BLOCK_SIZE, + >::try_from(*position)?); } - None => {} } } Err(Error::EfsHeaderNotFound) @@ -1096,8 +1029,8 @@ impl< [0; ERASABLE_BLOCK_SIZE]; storage.read_erasable_block(efh_beginning, &mut xbuf)?; let efh = header_from_collection::(&xbuf[..]) - .ok_or_else(|| Error::EfsHeaderNotFound)?; - if efh.signature().ok().or(Some(0)).unwrap() != 0x55aa_55aa { + .ok_or(Error::EfsHeaderNotFound)?; + if efh.signature().ok().unwrap_or(0) != 0x55aa_55aa { return Err(Error::EfsHeaderNotFound); } @@ -1109,7 +1042,7 @@ impl< }) } pub fn create( - mut storage: T, + storage: T, processor_generation: ProcessorGeneration, efh_beginning: Location, amd_physical_mode_mmio_size: Option, @@ -1144,7 +1077,11 @@ impl< )?, &buf, )?; - Self::load(storage, Some(processor_generation), amd_physical_mode_mmio_size) + Self::load( + storage, + Some(processor_generation), + amd_physical_mode_mmio_size, + ) } /// Note: Either psp_directory or psp_combo_directory will succeed--but not both. @@ -1152,11 +1089,13 @@ impl< &self, ) -> Result> { let psp_directory_table_location = - self.efh.psp_directory_table_location_zen().ok().or(Some(0xffff_ffff)).unwrap(); + self.efh.psp_directory_table_location_zen() + .ok() + .unwrap_or(0xffff_ffff); if psp_directory_table_location == 0xffff_ffff { Err(Error::PspDirectoryHeaderNotFound) } else { - let directory = match PspDirectory::load( + match PspDirectory::load( &self.storage, psp_directory_table_location, self.amd_physical_mode_mmio_size, @@ -1180,8 +1119,7 @@ impl< .efh .psp_directory_table_location_naples() .ok() - .or(Some(0xffff_ffff)) - .unwrap(); + .unwrap_or(0xffff_ffff); if addr == 0xffff_ffff { addr } else { @@ -1213,11 +1151,13 @@ impl< &self, ) -> Result> { let psp_directory_table_location = - self.efh.psp_directory_table_location_zen().ok().or(Some(0xffff_ffff)).unwrap(); + self.efh.psp_directory_table_location_zen() + .ok() + .unwrap_or(0xffff_ffff); if psp_directory_table_location == 0xffff_ffff { Err(Error::PspDirectoryHeaderNotFound) } else { - let directory = match ComboDirectory::load( + match ComboDirectory::load( &self.storage, psp_directory_table_location, self.amd_physical_mode_mmio_size, @@ -1240,8 +1180,7 @@ impl< .efh .psp_directory_table_location_naples() .ok() - .or(Some(0xffff_ffff)) - .unwrap(); + .unwrap_or(0xffff_ffff); if addr == 0xffff_ffff { addr } else { @@ -1277,11 +1216,7 @@ impl< let psp_directory_table_location = main_directory.entry_location(&entry)?; let directory = PspDirectory::load( &self.storage, - psp_directory_table_location - .try_into() - .map_err(|_| { - Error::DirectoryRangeCheck - })?, + psp_directory_table_location, self.amd_physical_mode_mmio_size, )?; return Ok(directory); @@ -1303,76 +1238,106 @@ impl< &self, processor_generation: Option, ) -> Result> { - fn de_mmio(v: u32, amd_physical_mode_mmio_size: Option) -> u32 { + fn de_mmio( + v: u32, + amd_physical_mode_mmio_size: Option, + ) -> u32 { if v == 0xffff_ffff || v == 0 { 0xffff_ffff - } else { - if let Some(amd_physical_mode_mmio_size) = amd_physical_mode_mmio_size { - match mmio_decode(v, amd_physical_mode_mmio_size) { - Ok(v) => v, - Err(Error::DirectoryTypeMismatch) => { - // Rome is a grey-area that supports both MMIO addresses and offsets - if v < amd_physical_mode_mmio_size { + } else if let Some(amd_physical_mode_mmio_size) = + amd_physical_mode_mmio_size + { + match mmio_decode( + v, + amd_physical_mode_mmio_size, + ) { + Ok(v) => v, + Err(Error::DirectoryTypeMismatch) => { + // Rome is a grey-area that supports both MMIO addresses and offsets + if v < amd_physical_mode_mmio_size { v } else { 0xffff_ffff } - } - Err(_) => { - 0xffff_ffff - } } - } else { - 0xffff_ffff + Err(_) => 0xffff_ffff, } + } else { + 0xffff_ffff } } let efh = &self.efh; - let amd_physical_mode_mmio_size = self.amd_physical_mode_mmio_size; + let amd_physical_mode_mmio_size = + self.amd_physical_mode_mmio_size; let invalid_position = 0xffff_ffffu32; let positions = match processor_generation { Some(ProcessorGeneration::Milan) => [ - efh.bhd_directory_table_milan().ok().or(Some(invalid_position)).unwrap(), + efh.bhd_directory_table_milan() + .ok() + .unwrap_or(invalid_position), invalid_position, invalid_position, invalid_position, ], Some(ProcessorGeneration::Rome) => [ - de_mmio(efh.bhd_directory_tables[2].get(), amd_physical_mode_mmio_size), + de_mmio( + efh.bhd_directory_tables[2].get(), + amd_physical_mode_mmio_size, + ), invalid_position, invalid_position, invalid_position, ], Some(ProcessorGeneration::Naples) => [ - de_mmio(efh.bhd_directory_tables[0].get(), amd_physical_mode_mmio_size), + de_mmio( + efh.bhd_directory_tables[0].get(), + amd_physical_mode_mmio_size, + ), invalid_position, invalid_position, invalid_position, ], - None => [ // allow all (used for example for overlap checking) - efh.bhd_directory_table_milan().ok().or(Some(invalid_position)).unwrap(), - - de_mmio(efh.bhd_directory_tables[2].get(), amd_physical_mode_mmio_size), - de_mmio(efh.bhd_directory_tables[1].get(), amd_physical_mode_mmio_size), - de_mmio(efh.bhd_directory_tables[0].get(), amd_physical_mode_mmio_size), - ] + None => [ + // allow all (used for example for overlap checking) + efh.bhd_directory_table_milan() + .ok() + .unwrap_or(invalid_position), + de_mmio( + efh.bhd_directory_tables[2].get(), + amd_physical_mode_mmio_size, + ), + de_mmio( + efh.bhd_directory_tables[1].get(), + amd_physical_mode_mmio_size, + ), + de_mmio( + efh.bhd_directory_tables[0].get(), + amd_physical_mode_mmio_size, + ), + ], }; Ok(EfhBhdsIterator { storage: &self.storage, physical_address_mode: self.physical_address_mode(), - positions: positions, + positions, index_into_positions: 0, - amd_physical_mode_mmio_size: self.amd_physical_mode_mmio_size, + amd_physical_mode_mmio_size: self + .amd_physical_mode_mmio_size, }) } - /// Return the directory matching PROCESSOR_GENERATION, - /// or any directory if that is None. - pub fn bhd_directory(&self, processor_generation: Option) - -> Result> - { - for bhd_directory in self.bhd_directories(processor_generation).unwrap() { - return Ok(bhd_directory); + /// Return the directory matching PROCESSOR_GENERATION, + /// or any directory if that is None. + pub fn bhd_directory( + &self, + processor_generation: Option, + ) -> Result> { + if let Some(bhd_directory) = self + .bhd_directories(processor_generation) + .unwrap() + .next() + { + return Ok(bhd_directory); } Err(Error::BhdDirectoryHeaderNotFound) } @@ -1416,10 +1381,7 @@ impl< return Err(Error::Overlap); } let (reference_beginning, reference_end) = ( - Location::from( - psp_directory - .contents_beginning(), - ), + psp_directory.contents_beginning(), Location::from( psp_directory.contents_end(), ), @@ -1450,9 +1412,7 @@ impl< return Err(Error::Overlap); } let (reference_beginning, reference_end) = ( - Location::from( - bhd_directory.contents_beginning(), - ), + bhd_directory.contents_beginning(), Location::from(bhd_directory.contents_end()), ); let intersection_beginning = @@ -1468,11 +1428,8 @@ impl< fn write_efh(&mut self) -> Result<()> { let mut buf: [u8; ERASABLE_BLOCK_SIZE] = [0xFF; ERASABLE_BLOCK_SIZE]; - match header_from_collection_mut(&mut buf[..]) { - Some(item) => { - *item = self.efh; - } - None => {} + if let Some(item) = header_from_collection_mut(&mut buf[..]) { + *item = self.efh; } self.storage @@ -1516,17 +1473,19 @@ impl< match default_entry_address_mode { AddressMode::PhysicalAddress => { if !self.physical_address_mode() { - return Err(Error::DirectoryTypeMismatch) + return Err( + Error::DirectoryTypeMismatch, + ); } } AddressMode::EfsRelativeOffset => { if self.physical_address_mode() { - return Err(Error::DirectoryTypeMismatch) + return Err( + Error::DirectoryTypeMismatch, + ); } } - _ => { - return Err(Error::DirectoryTypeMismatch) - } + _ => return Err(Error::DirectoryTypeMismatch), } match self.bhd_directories(None) { Ok(items) => { @@ -1545,7 +1504,9 @@ impl< if self.efh.compatible_with_processor_generation( ProcessorGeneration::Milan, ) { - self.efh.set_bhd_directory_table_milan(beginning.into()); + self.efh.set_bhd_directory_table_milan( + beginning.into(), + ); // FIXME: ensure that the others are unset? } else { self.efh.bhd_directory_tables[2].set(beginning.into()); @@ -1554,7 +1515,7 @@ impl< self.write_efh()?; let result = BhdDirectory::create( default_entry_address_mode, - &mut self.storage, + &self.storage, beginning, end, *b"$BHD", @@ -1573,17 +1534,19 @@ impl< match default_entry_address_mode { AddressMode::PhysicalAddress => { if !self.physical_address_mode() { - return Err(Error::DirectoryTypeMismatch) + return Err( + Error::DirectoryTypeMismatch, + ); } } AddressMode::EfsRelativeOffset => { if self.physical_address_mode() { - return Err(Error::DirectoryTypeMismatch) + return Err( + Error::DirectoryTypeMismatch, + ); } } - _ => { - return Err(Error::DirectoryTypeMismatch) - } + _ => return Err(Error::DirectoryTypeMismatch), } match self.psp_directory() { Err(Error::PspDirectoryHeaderNotFound) => {} @@ -1603,7 +1566,7 @@ impl< self.write_efh()?; let result = PspDirectory::create( default_entry_address_mode, - &mut self.storage, + &self.storage, beginning, end, *b"$PSP", @@ -1621,7 +1584,11 @@ impl< Location::from(beginning), Location::from(end), )?; - self.psp_directory()?.create_subdirectory(beginning, end, self.amd_physical_mode_mmio_size) + self.psp_directory()?.create_subdirectory( + beginning, + end, + self.amd_physical_mode_mmio_size, + ) } /*pub fn create_second_level_bhd_directory<'c>(&self, bhd_directory: &mut BhdDirectory<'c, T, ERASABLE_BLOCK_SIZE>, beginning: ErasableLocation, end: ErasableLocation) -> Result> { diff --git a/src/lib.rs b/src/lib.rs index 14d9c00..b8cbc82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,22 +1,21 @@ #![cfg_attr(not(feature = "std"), no_std)] +mod adapters; mod amdfletcher32; mod efs; mod ondisk; -mod adapters; +mod serializers; mod struct_accessors; mod types; -mod serializers; +pub use crate::efs::preferred_efh_location; pub use crate::efs::BhdDirectory; pub use crate::efs::Efs; pub use crate::efs::ProcessorGeneration; pub use crate::efs::PspDirectory; +pub use crate::ondisk::ValueOrLocation; pub use ondisk::*; pub use types::Error; pub use types::Result; -pub use crate::ondisk::ValueOrLocation; -pub use crate::efs::DirectoryFrontend; -pub use crate::efs::preferred_efh_location; #[cfg(test)] mod tests { diff --git a/src/ondisk.rs b/src/ondisk.rs index 182682c..26a46c9 100644 --- a/src/ondisk.rs +++ b/src/ondisk.rs @@ -1,21 +1,22 @@ // This file contains the AMD firmware Flash on-disk format. Please only change it in coordination with the AMD firmware team. Even then, you probably shouldn't. +use core::mem::size_of; +use crate::struct_accessors::make_accessors; +use crate::struct_accessors::DummyErrorChecks; +use crate::struct_accessors::Getter; +use crate::struct_accessors::Setter; use crate::types::Error; use crate::types::Result; use amd_flash::Location; use byteorder::LittleEndian; -use core::convert::TryInto; use core::convert::TryFrom; +use core::convert::TryInto; use modular_bitfield::prelude::*; -use num_traits::FromPrimitive; use num_derive::FromPrimitive; use num_derive::ToPrimitive; -use crate::struct_accessors::make_accessors; -use crate::struct_accessors::Getter; -use crate::struct_accessors::Setter; -use crate::struct_accessors::DummyErrorChecks; +use num_traits::FromPrimitive; use strum_macros::EnumString; -use zerocopy::{AsBytes, FromBytes, LayoutVerified, Unaligned, U32, U64}; +use zerocopy::{AsBytes, FromBytes, LayoutVerified, Unaligned, U32}; //use crate::configs; /// Given *BUF (a collection of multiple items), retrieves the first of the items and returns it. @@ -41,7 +42,6 @@ pub fn header_from_collection<'a, T: Sized + FromBytes>( } type LU32 = U32; -type LU64 = U64; // The first one is recommended by AMD; the last one is always used in practice. pub const EFH_POSITION: [Location; 6] = [ @@ -247,7 +247,15 @@ impl Default for Efh { } #[repr(i8)] -#[derive(Debug, PartialEq, FromPrimitive, Clone, Copy, EnumString, strum_macros::EnumIter)] +#[derive( + Debug, + PartialEq, + FromPrimitive, + Clone, + Copy, + EnumString, + strum_macros::EnumIter, +)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum ProcessorGeneration { @@ -287,7 +295,8 @@ impl Efh { generation => { let generation: u8 = generation as u8; assert!(generation < 16); - self.efs_generations.get() & (1 << generation) == 0 + self.efs_generations.get() & (1 << generation) == + 0 } } } @@ -309,7 +318,9 @@ impl Efh { } } -#[derive(Debug, PartialEq, Eq, FromPrimitive, Clone, Copy, BitfieldSpecifier)] +#[derive( + Debug, PartialEq, Eq, FromPrimitive, Clone, Copy, BitfieldSpecifier, +)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub enum AddressMode { @@ -322,47 +333,60 @@ pub enum AddressMode { EntryRelativeOffset = 3, // x; ImageBaseRelativeOffset == DirectoryRelativeOffset; not Base } -pub(crate) const WEAK_ADDRESS_MODE: AddressMode = AddressMode::DirectoryRelativeOffset; +pub(crate) const WEAK_ADDRESS_MODE: AddressMode = + AddressMode::DirectoryRelativeOffset; -impl DummyErrorChecks for AddressMode { -} +impl DummyErrorChecks for AddressMode {} pub enum ValueOrLocation { Value(u64), PhysicalAddress(u32), - EfsRelativeOffset(u32), - DirectoryRelativeOffset(u32), - EntryRelativeOffset(u32), + EfsRelativeOffset(u32), + DirectoryRelativeOffset(u32), + EntryRelativeOffset(u32), } impl core::fmt::Debug for ValueOrLocation { fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { Self::Value(x) => write!(fmt, "Value({:x?})", x), - Self::PhysicalAddress(x) => write!(fmt, "PhysicalAddress({:#x?})", x), - Self::EfsRelativeOffset(x) => write!(fmt, "EfsRelativeOffset({:#x?})", x), - Self::DirectoryRelativeOffset(x) => write!(fmt, "DirectoryRelativeOffset({:#x?})", x), - Self::EntryRelativeOffset(x) => write!(fmt, "EntryRelativeOffset({:#x?})", x), + Self::PhysicalAddress(x) => { + write!(fmt, "PhysicalAddress({:#x?})", x) + } + Self::EfsRelativeOffset(x) => { + write!(fmt, "EfsRelativeOffset({:#x?})", x) + } + Self::DirectoryRelativeOffset(x) => write!( + fmt, + "DirectoryRelativeOffset({:#x?})", + x + ), + Self::EntryRelativeOffset(x) => { + write!(fmt, "EntryRelativeOffset({:#x?})", x) + } } } } -pub(crate) fn mmio_encode(value: Location, amd_physical_mode_mmio_size: Option) -> Result { +pub(crate) fn mmio_encode( + value: Location, + amd_physical_mode_mmio_size: Option, +) -> Result { let mmio_address_lower = match amd_physical_mode_mmio_size { - None | Some(0) => { - return Err(Error::DirectoryTypeMismatch) - } + None | Some(0) => return Err(Error::DirectoryTypeMismatch), Some(x) => 1 + (0xFFFF_FFFFu32 - x), }; - Ok(value.checked_add(mmio_address_lower).ok_or(Error::DirectoryTypeMismatch)?) + Ok(value.checked_add(mmio_address_lower) + .ok_or(Error::DirectoryTypeMismatch)?) } -pub(crate) fn mmio_decode(value: u32, amd_physical_mode_mmio_size: u32) -> Result { +pub(crate) fn mmio_decode( + value: u32, + amd_physical_mode_mmio_size: u32, +) -> Result { let mmio_address_lower = match amd_physical_mode_mmio_size { - 0 => { - return Err(Error::DirectoryTypeMismatch) - } - x => 1 + (0xFFFF_FFFFu32 - x) + 0 => return Err(Error::DirectoryTypeMismatch), + x => 1 + (0xFFFF_FFFFu32 - x), }; if value >= mmio_address_lower { Ok(value - mmio_address_lower) @@ -372,53 +396,110 @@ pub(crate) fn mmio_decode(value: u32, amd_physical_mode_mmio_size: u32) -> Resul } impl ValueOrLocation { - pub(crate) fn new_from_raw_location(directory_address_mode: AddressMode, source: u64) -> Result { + fn effective_address_mode(directory_address_mode: AddressMode, entry_address_mode: AddressMode) -> AddressMode { + if directory_address_mode == WEAK_ADDRESS_MODE { + entry_address_mode + } else { + directory_address_mode + } + } + fn is_entry_address_mode_effective(directory_address_mode: AddressMode, entry_address_mode: AddressMode) -> bool { + Self::effective_address_mode(directory_address_mode, entry_address_mode) == entry_address_mode + } + + pub(crate) fn new_from_raw_location( + directory_address_mode: AddressMode, + source: u64, + ) -> Result { let entry_address_mode = (source & 0xC000_0000_0000_0000) >> 62; - let entry_address_mode = AddressMode::from_u64(entry_address_mode).unwrap(); - let value = u32::try_from(source & !0xC000_0000_0000_0000).map_err(|_| Error::DirectoryPayloadRangeCheck)?; - let address_mode = match directory_address_mode { - WEAK_ADDRESS_MODE => entry_address_mode, - x => x - }; + let entry_address_mode = + AddressMode::from_u64(entry_address_mode).unwrap(); + let value = u32::try_from(source & !0xC000_0000_0000_0000) + .map_err(|_| Error::DirectoryPayloadRangeCheck)?; + let address_mode = Self::effective_address_mode( + directory_address_mode, + entry_address_mode + ); Ok(match address_mode { - AddressMode::PhysicalAddress => Self::PhysicalAddress(value), - AddressMode::EfsRelativeOffset => Self::EfsRelativeOffset(value), - AddressMode::DirectoryRelativeOffset => Self::DirectoryRelativeOffset(value), - AddressMode::EntryRelativeOffset => Self::EntryRelativeOffset(value), + AddressMode::PhysicalAddress => { + Self::PhysicalAddress(value) + } + AddressMode::EfsRelativeOffset => { + Self::EfsRelativeOffset(value) + } + AddressMode::DirectoryRelativeOffset => { + Self::DirectoryRelativeOffset(value) + } + AddressMode::EntryRelativeOffset => { + Self::EntryRelativeOffset(value) + } }) } - pub(crate) fn try_into_raw_location(&self, directory_address_mode: AddressMode) -> Result { + + pub(crate) fn try_into_raw_location( + &self, + directory_address_mode: AddressMode, + ) -> Result { match self { - ValueOrLocation::Value(x) => { + ValueOrLocation::Value(_) => { Err(Error::EntryTypeMismatch) } ValueOrLocation::PhysicalAddress(x) => { - if directory_address_mode == AddressMode::PhysicalAddress || directory_address_mode == WEAK_ADDRESS_MODE { - let v = u64::from(*x) | 0; + if Self::is_entry_address_mode_effective( + directory_address_mode, + AddressMode::PhysicalAddress + ) { + // AMD retrofitted (introduced) two + // flag bits at the top bits in Milan. + // + // In Rome, you actually COULD use + // all the bits. + // + // Newer platform do not regularily use + // AddressMode::PhysicalAddress anyway. + // + // But if someone uses + // AddressMode::PhysicalAddress, + // they might do it on Rome and use + // those two top bits as part of the + // address. + let v = u64::from(*x); Ok(v) } else { Err(Error::EntryTypeMismatch) } } ValueOrLocation::EfsRelativeOffset(x) => { - if directory_address_mode == AddressMode::EfsRelativeOffset || directory_address_mode == WEAK_ADDRESS_MODE { - let v = u64::from(*x) | 0x4000_0000_0000_0000; + if Self::is_entry_address_mode_effective( + directory_address_mode, + AddressMode::EfsRelativeOffset + ) { + let v = u64::from(*x) | + 0x4000_0000_0000_0000; Ok(v) } else { Err(Error::EntryTypeMismatch) } } ValueOrLocation::DirectoryRelativeOffset(x) => { - if directory_address_mode == AddressMode::DirectoryRelativeOffset || directory_address_mode == WEAK_ADDRESS_MODE { - let v = u64::from(*x) | 0x8000_0000_0000_0000; + if Self::is_entry_address_mode_effective( + directory_address_mode, + AddressMode::DirectoryRelativeOffset + ) { + let v = u64::from(*x) | + 0x8000_0000_0000_0000; Ok(v) } else { Err(Error::EntryTypeMismatch) } } ValueOrLocation::EntryRelativeOffset(x) => { - if directory_address_mode == AddressMode::EntryRelativeOffset && directory_address_mode == WEAK_ADDRESS_MODE { - let v = u64::from(*x) | 0xC000_0000_0000_0000; + if Self::is_entry_address_mode_effective( + directory_address_mode, + AddressMode::EntryRelativeOffset + ) { + let v = u64::from(*x) | + 0xC000_0000_0000_0000; Ok(v) } else { Err(Error::EntryTypeMismatch) @@ -428,7 +509,6 @@ impl ValueOrLocation { } } - /// XXX: If I move this to struct_accessors, it doesn't work anymore. /// Since modular_bitfield has a lot of the things already, provide a macro @@ -512,16 +592,6 @@ impl DirectoryAdditionalInfo { result.set_spi_block_size_checked(value)?; Ok(result) } -/* - pub fn with_spi_block_size( - &mut self, - value: u16, - ) -> Self { - let mut result = *self; - result.set_spi_block_size_checked(value).unwrap(); // FIXME - result - } -*/ pub fn spi_block_size_or_err( &self, ) -> core::result::Result< @@ -730,8 +800,7 @@ pub enum PspDirectoryEntryType { MpmSecurityDriver = 0x89, } -impl DummyErrorChecks for PspDirectoryEntryType { -} +impl DummyErrorChecks for PspDirectoryEntryType {} /// For 32 MiB SPI Flash, which half to map to MMIO 0xff00_0000. #[derive(Debug, PartialEq, FromPrimitive, Clone, Copy, BitfieldSpecifier)] @@ -743,8 +812,7 @@ pub enum PspSoftFuseChain32MiBSpiDecoding { UpperHalf = 1, } -impl DummyErrorChecks for PspSoftFuseChain32MiBSpiDecoding { -} +impl DummyErrorChecks for PspSoftFuseChain32MiBSpiDecoding {} #[derive(Debug, PartialEq, FromPrimitive, Clone, Copy, BitfieldSpecifier)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -755,8 +823,7 @@ pub enum PspSoftFuseChainPostCodeDecoding { Espi = 1, } -impl DummyErrorChecks for PspSoftFuseChainPostCodeDecoding { -} +impl DummyErrorChecks for PspSoftFuseChainPostCodeDecoding {} make_bitfield_serde! { #[bitfield(bits = 64)] @@ -804,8 +871,7 @@ pub enum PspDirectoryRomId { SpiCs2 = 1, } -impl DummyErrorChecks for PspDirectoryRomId { -} +impl DummyErrorChecks for PspDirectoryRomId {} impl Default for PspDirectoryRomId { fn default() -> Self { @@ -824,8 +890,7 @@ pub enum BhdDirectoryRomId { SpiCs2 = 1, } -impl DummyErrorChecks for BhdDirectoryRomId { -} +impl DummyErrorChecks for BhdDirectoryRomId {} impl Default for BhdDirectoryRomId { fn default() -> Self { @@ -838,6 +903,7 @@ make_bitfield_serde! { #[bitfield(bits = 128)] pub struct PspDirectoryEntry { #[bits = 8] + #[allow(non_snake_case)] pub type_: PspDirectoryEntryType : pub get PspDirectoryEntryType : pub set PspDirectoryEntryType, pub sub_program: B8 : pub get u8 : pub set u8, // function of AMD Family and Model; only useful for types 8, 0x24, 0x25 pub rom_id: PspDirectoryRomId : pub get PspDirectoryRomId : pub set PspDirectoryRomId, @@ -849,41 +915,26 @@ make_bitfield_serde! { } pub trait DirectoryEntry { - fn source(&self, directory_address_mode: AddressMode) -> Result; + fn source( + &self, + directory_address_mode: AddressMode, + ) -> Result; fn size(&self) -> Option; /// Note: This can also modify size as a side effect. - fn set_source(&mut self, directory_address_mode: AddressMode, value: ValueOrLocation) -> Result<()>; + fn set_source( + &mut self, + directory_address_mode: AddressMode, + value: ValueOrLocation, + ) -> Result<()>; fn set_size(&mut self, value: Option); } pub trait DirectoryEntrySerde: Sized { - fn from_bytes_b(source: &[u8]) -> Option; + fn from_slice(source: &[u8]) -> Option; fn copy_into_slice(&self, destination: &mut [u8]); } impl DirectoryEntrySerde for PspDirectoryEntry { - fn from_bytes_b(source: &[u8]) -> Option { - if source.len() != 16 { - None - } else { - let source: [u8; 16] = [ - source[0], - source[1], - source[2], - source[3], - source[4], - source[5], - source[6], - source[7], - source[8], - source[9], - source[10], - source[11], - source[12], - source[13], - source[14], - source[15] - ]; - Some(Self::from_bytes(source)) - } + fn from_slice(source: &[u8]) -> Option { + <[u8; size_of::()]>::try_from(source).ok().map(|s| Self::from_bytes(s)) } fn copy_into_slice(&self, destination: &mut [u8]) { destination.copy_from_slice(&self.into_bytes()) @@ -893,11 +944,13 @@ impl DirectoryEntrySerde for PspDirectoryEntry { impl PspDirectoryEntry { const SIZE_VALUE_MARKER: u32 = 0xFFFF_FFFF; pub fn type_or_err(&self) -> Result { - self.type__or_err() - .map_err(|_| Error::EntryTypeMismatch) + self.type__or_err().map_err(|_| Error::EntryTypeMismatch) } /// Note: Caller can modify other attributes using the with_ accessors. - pub fn new_value(type_: PspDirectoryEntryType, value: u64) -> Result { + pub fn new_value( + type_: PspDirectoryEntryType, + value: u64, + ) -> Result { Ok(Self::new() .with_type_(type_.into()) .with_internal_size(Self::SIZE_VALUE_MARKER.into()) @@ -910,8 +963,7 @@ impl PspDirectoryEntry { size: Option, source: Option, ) -> Result { - let mut result = Self::new() - .with_type_(type_.into()); + let mut result = Self::new().with_type_(type_.into()); result.set_size(size); if let Some(x) = source { result.set_source(directory_address_mode, x)?; @@ -921,16 +973,26 @@ impl PspDirectoryEntry { } impl DirectoryEntry for PspDirectoryEntry { - fn source(&self, directory_address_mode: AddressMode) -> Result { + fn source( + &self, + directory_address_mode: AddressMode, + ) -> Result { let source = self.internal_source(); let size = self.internal_size(); if size == Self::SIZE_VALUE_MARKER { Ok(ValueOrLocation::Value(source)) } else { - ValueOrLocation::new_from_raw_location(directory_address_mode, source) + ValueOrLocation::new_from_raw_location( + directory_address_mode, + source, + ) } } - fn set_source(&mut self, directory_address_mode: AddressMode, value: ValueOrLocation) -> Result<()> { + fn set_source( + &mut self, + directory_address_mode: AddressMode, + value: ValueOrLocation, + ) -> Result<()> { match value { ValueOrLocation::Value(v) => { self.set_internal_size(Self::SIZE_VALUE_MARKER); @@ -938,7 +1000,9 @@ impl DirectoryEntry for PspDirectoryEntry { Ok(()) } x => { - let v = x.try_into_raw_location(directory_address_mode)?; + let v = x.try_into_raw_location( + directory_address_mode, + )?; self.set_internal_source(v); Ok(()) } @@ -961,7 +1025,6 @@ impl DirectoryEntry for PspDirectoryEntry { } }) } - } impl core::fmt::Debug for PspDirectoryEntry { @@ -1067,8 +1130,7 @@ pub enum BhdDirectoryEntryType { SecondLevelDirectory = 0x70, // also a BhdDirectory } -impl DummyErrorChecks for BhdDirectoryEntryType { -} +impl DummyErrorChecks for BhdDirectoryEntryType {} #[derive(Copy, Clone, Debug, FromPrimitive, BitfieldSpecifier)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -1087,32 +1149,7 @@ impl Default for BhdDirectoryEntryRegionType { } } -impl DummyErrorChecks for BhdDirectoryEntryRegionType { -} - -fn read_only_default() -> bool { - false // for X86: the only choice -} - -fn reset_image_default() -> bool { - false -} - -fn copy_image_default() -> bool { - false -} - -fn compressed_default() -> bool { - false -} - -fn instance_default() -> u8 { - 0 -} - -fn sub_program_default() -> u8 { - 0 -} +impl DummyErrorChecks for BhdDirectoryEntryRegionType {} make_bitfield_serde! { #[bitfield(bits = 192)] @@ -1120,6 +1157,7 @@ make_bitfield_serde! { #[repr(C, packed)] pub struct BhdDirectoryEntry { #[bits = 8] + #[allow(non_snake_case)] pub type_: BhdDirectoryEntryType : pub get BhdDirectoryEntryType : pub set BhdDirectoryEntryType, #[bits = 8] pub region_type: BhdDirectoryEntryRegionType : pub get BhdDirectoryEntryRegionType : pub set BhdDirectoryEntryRegionType, @@ -1140,37 +1178,8 @@ make_bitfield_serde! { } impl DirectoryEntrySerde for BhdDirectoryEntry { - fn from_bytes_b(source: &[u8]) -> Option { - if source.len() != 24 { - None - } else { - Some(Self::from_bytes([ - source[0], - source[1], - source[2], - source[3], - source[4], - source[5], - source[6], - source[7], - source[8], - source[9], - source[10], - source[11], - source[12], - source[13], - source[14], - source[15], - source[16], - source[17], - source[18], - source[19], - source[20], - source[21], - source[22], - source[23], - ])) - } + fn from_slice(source: &[u8]) -> Option { + <[u8; size_of::()]>::try_from(source).ok().map(|s| Self::from_bytes(s)) } fn copy_into_slice(&self, destination: &mut [u8]) { destination.copy_from_slice(&self.into_bytes()) @@ -1181,8 +1190,7 @@ impl BhdDirectoryEntry { const SIZE_VALUE_MARKER: u32 = 0xFFFF_FFFF; const DESTINATION_NONE_MARKER: u64 = 0xffff_ffff_ffff_ffff; pub fn type_or_err(&self) -> Result { - self.type__or_err() - .map_err(|_| Error::EntryTypeMismatch) + self.type__or_err().map_err(|_| Error::EntryTypeMismatch) } pub fn destination_location(&self) -> Option { @@ -1202,8 +1210,9 @@ impl BhdDirectoryEntry { destination_location: Option, ) -> Result { let mut result = Self::new() - .with_type_(type_.into()) - .with_internal_destination_location(match destination_location { + .with_type_(type_.into()) + .with_internal_destination_location( + match destination_location { None => Self::DESTINATION_NONE_MARKER, Some(x) => { if x == Self::DESTINATION_NONE_MARKER { @@ -1212,7 +1221,8 @@ impl BhdDirectoryEntry { x } } - .into()); + .into(), + ); result.set_size(size); if let Some(x) = source { result.set_source(directory_address_mode, x)?; @@ -1224,20 +1234,32 @@ impl BhdDirectoryEntry { } impl DirectoryEntry for BhdDirectoryEntry { - fn source(&self, directory_address_mode: AddressMode) -> Result { + fn source( + &self, + directory_address_mode: AddressMode, + ) -> Result { let size = self.internal_size(); let source = self.internal_source(); if size == Self::SIZE_VALUE_MARKER { Ok(ValueOrLocation::Value(source)) } else { let source = self.internal_source(); - ValueOrLocation::new_from_raw_location(directory_address_mode, source) + ValueOrLocation::new_from_raw_location( + directory_address_mode, + source, + ) } } - fn set_source(&mut self, directory_address_mode: AddressMode, value: ValueOrLocation) -> Result<()> { + fn set_source( + &mut self, + directory_address_mode: AddressMode, + value: ValueOrLocation, + ) -> Result<()> { match value { ValueOrLocation::Value(v) => { - if self.internal_size() == Self::SIZE_VALUE_MARKER { + if self.internal_size() == + Self::SIZE_VALUE_MARKER + { self.set_internal_source(v); Ok(()) } else { @@ -1245,7 +1267,9 @@ impl DirectoryEntry for BhdDirectoryEntry { } } x => { - let v = x.try_into_raw_location(directory_address_mode)?; + let v = x.try_into_raw_location( + directory_address_mode, + )?; self.set_internal_source(v); Ok(()) } @@ -1335,8 +1359,7 @@ impl DirectoryHeader for ComboDirectoryHeader { fn additional_info(&self) -> DirectoryAdditionalInfo { DirectoryAdditionalInfo::from(0) } - fn set_additional_info(&mut self, value: DirectoryAdditionalInfo) { - } + fn set_additional_info(&mut self, value: DirectoryAdditionalInfo) {} fn total_entries(&self) -> u32 { self.total_entries.get() } @@ -1346,12 +1369,11 @@ impl DirectoryHeader for ComboDirectoryHeader { fn checksum(&self) -> u32 { self.checksum.get() } - fn set_checksum(&mut self, value: u32) { - self.checksum.set(value) - } + fn set_checksum(&mut self, value: u32) { + self.checksum.set(value) + } } - impl ComboDirectoryHeader { pub fn new(cookie: [u8; 4]) -> Result { if cookie == *b"2PSP" || cookie == *b"2BHD" { @@ -1370,48 +1392,24 @@ impl ComboDirectoryHeader { #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[non_exhaustive] pub enum ComboDirectoryEntryFilter { - PspId(u32), // = 0, + PspId(u32), // = 0, ChipFamilyId(u32), // = 1, } -make_bitfield_serde! { - #[derive(Clone, Copy)] - #[bitfield] - pub struct ComboDirectoryEntry { - pub(crate) internal_key: B32, // 0-PSP ID; 1-chip family ID - pub(crate) internal_value: B32, - pub(crate) internal_source: B64, // that's the (Psp|Bhd) directory entry location. Note: If 32 bit high nibble is set, then that's a physical address - } +#[derive(Clone, Copy)] +#[bitfield] +pub struct ComboDirectoryEntry { + pub(crate) internal_key: B32, // 0-PSP ID; 1-chip family ID + pub(crate) internal_value: B32, + pub(crate) internal_source: B64, // that's the (Psp|Bhd) directory entry location. Note: If 32 bit high nibble is set, then that's a physical address } impl DirectoryEntrySerde for ComboDirectoryEntry { - fn from_bytes_b(source: &[u8]) -> Option { - if source.len() != 16 { - None - } else { - let source = [ - source[0], - source[1], - source[2], - source[3], - source[4], - source[5], - source[6], - source[7], - source[8], - source[9], - source[10], - source[11], - source[12], - source[13], - source[14], - source[15], - ]; - Some(Self::from_bytes(source)) - } + fn from_slice(source: &[u8]) -> Option { + <[u8; size_of::()]>::try_from(source).ok().map(|s| Self::from_bytes(s)) } fn copy_into_slice(&self, destination: &mut [u8]) { - destination.copy_from_slice(&self.into_bytes()) + destination.copy_from_slice(&self.into_bytes()) } } @@ -1427,18 +1425,31 @@ impl core::fmt::Debug for ComboDirectoryEntry { } } -impl DirectoryEntry for ComboDirectoryEntry { // XXX - fn source(&self, directory_address_mode: AddressMode) -> Result { +impl DirectoryEntry for ComboDirectoryEntry { + // XXX + fn source( + &self, + directory_address_mode: AddressMode, + ) -> Result { let source = self.internal_source(); - ValueOrLocation::new_from_raw_location(directory_address_mode, source) + ValueOrLocation::new_from_raw_location( + directory_address_mode, + source, + ) } - fn set_source(&mut self, directory_address_mode: AddressMode, value: ValueOrLocation) -> Result<()> { + fn set_source( + &mut self, + directory_address_mode: AddressMode, + value: ValueOrLocation, + ) -> Result<()> { match value { - ValueOrLocation::Value(v) => { + ValueOrLocation::Value(_) => { Err(Error::EntryTypeMismatch) } x => { - let v = x.try_into_raw_location(directory_address_mode)?; + let v = x.try_into_raw_location( + directory_address_mode, + )?; self.set_internal_source(v.into()); Ok(()) } @@ -1446,7 +1457,7 @@ impl DirectoryEntry for ComboDirectoryEntry { // XXX } fn size(&self) -> Option { None - } + } fn set_size(&mut self, value: Option) { assert!(false); } @@ -1457,15 +1468,9 @@ impl ComboDirectoryEntry { let key = self.internal_key(); let value = self.internal_value(); match key { - 0 => { - Ok(ComboDirectoryEntryFilter::PspId(value)) - } - 1 => { - Ok(ComboDirectoryEntryFilter::ChipFamilyId(value)) - } - _ => { - Err(Error::DirectoryTypeMismatch) - } + 0 => Ok(ComboDirectoryEntryFilter::PspId(value)), + 1 => Ok(ComboDirectoryEntryFilter::ChipFamilyId(value)), + _ => Err(Error::DirectoryTypeMismatch), } } pub fn set_filter(&mut self, value: ComboDirectoryEntryFilter) { diff --git a/src/serializers.rs b/src/serializers.rs index a51d259..0d7478c 100644 --- a/src/serializers.rs +++ b/src/serializers.rs @@ -48,9 +48,21 @@ macro_rules! make_serde{($StructName:ident, $SerdeStructName:ident, [$($field_na } )} -make_serde!(EfhBulldozerSpiMode, SerdeEfhBulldozerSpiMode, [read_mode, fast_speed_new]); -make_serde!(EfhNaplesSpiMode, SerdeEfhNaplesSpiMode, [read_mode, fast_speed_new, micron_mode]); -make_serde!(EfhRomeSpiMode, SerdeEfhRomeSpiMode, [read_mode, fast_speed_new, micron_mode]); +make_serde!( + EfhBulldozerSpiMode, + SerdeEfhBulldozerSpiMode, + [read_mode, fast_speed_new] +); +make_serde!( + EfhNaplesSpiMode, + SerdeEfhNaplesSpiMode, + [read_mode, fast_speed_new, micron_mode] +); +make_serde!( + EfhRomeSpiMode, + SerdeEfhRomeSpiMode, + [read_mode, fast_speed_new, micron_mode] +); make_serde!( Efh, SerdeEfh, @@ -70,17 +82,25 @@ make_serde!( ] ); -make_serde!(DirectoryAdditionalInfo, SerdeDirectoryAdditionalInfo, [base_address, address_mode, max_size]); -make_serde!(PspSoftFuseChain, SerdePspSoftFuseChain, [ - secure_debug_unlock, - early_secure_debug_unlock, - unlock_token_in_nvram, - force_security_policy_loading_even_if_insecure, - load_diagnostic_bootloader, - disable_psp_debug_prints, - spi_decoding, - postcode_decoding, - skip_mp2_firmware_loading, - postcode_output_control_1byte, - force_recovery_booting -]); +make_serde!( + DirectoryAdditionalInfo, + SerdeDirectoryAdditionalInfo, + [base_address, address_mode, max_size] +); +make_serde!( + PspSoftFuseChain, + SerdePspSoftFuseChain, + [ + secure_debug_unlock, + early_secure_debug_unlock, + unlock_token_in_nvram, + force_security_policy_loading_even_if_insecure, + load_diagnostic_bootloader, + disable_psp_debug_prints, + spi_decoding, + postcode_decoding, + skip_mp2_firmware_loading, + postcode_output_control_1byte, + force_recovery_booting + ] +); diff --git a/src/struct_accessors.rs b/src/struct_accessors.rs index ee6970c..18382dd 100644 --- a/src/struct_accessors.rs +++ b/src/struct_accessors.rs @@ -134,21 +134,20 @@ impl Setter for BLU16 { /// The reason this exists is because our macros don't know whether or not /// the getters return Result--but they have to be able to call map_err /// on it in case these DO return Result. -pub(crate) trait DummyErrorChecks : Sized { - fn map_err(self, op: O) -> core::result::Result - where O: Fn(Self) -> F, { +pub(crate) trait DummyErrorChecks: Sized { + fn map_err(self, _op: O) -> core::result::Result + where + O: Fn(Self) -> F, + { Ok(self) - } + } } -impl DummyErrorChecks for u16 { -} +impl DummyErrorChecks for u16 {} -impl DummyErrorChecks for u8 { -} +impl DummyErrorChecks for u8 {} -impl DummyErrorChecks for bool { -} +impl DummyErrorChecks for bool {} /// This macro expects a struct as a parameter (attributes are fine) and then, /// first, defines the exact same struct, and also a more user-friendly struct diff --git a/src/types.rs b/src/types.rs index 2ffe6fb..87c482b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,10 +22,3 @@ impl From for Error { Error::Io(error) } } - -#[derive(Clone, Copy)] -#[repr(u8)] -pub enum LocationMode { - Offset = 0, - Mmio = 1, -}