Move Block handling into separate module and add BlockIterator
Convert Xlat::split_region_to_blocks into BlockIterator in order to
eliminate the use of Vec.
Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: Ie1b040a07c424c59e46eeadb1245b7c4a2033add
diff --git a/src/lib.rs b/src/lib.rs
index fec87cc..e8bd6eb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,12 +8,12 @@
extern crate alloc;
use core::iter::zip;
-use core::{fmt, panic};
+use core::panic;
use address::{PhysicalAddress, VirtualAddress, VirtualAddressRange};
use alloc::format;
-use alloc::string::{String, ToString};
-use alloc::vec::Vec;
+use alloc::string::String;
+use block::{Block, BlockIterator};
use log::debug;
use bitflags::bitflags;
@@ -28,6 +28,7 @@
use self::region_pool::{Region, RegionPool, RegionPoolError};
pub mod address;
+mod block;
mod descriptor;
mod granule;
pub mod kernel_space;
@@ -110,29 +111,6 @@
}
}
-#[derive(PartialEq)]
-struct Block {
- pa: PhysicalAddress,
- va: VirtualAddress,
- size: usize,
-}
-
-impl Block {
- fn new(pa: PhysicalAddress, va: VirtualAddress, size: usize) -> Self {
- Self { pa, va, size }
- }
-}
-
-impl fmt::Debug for Block {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Block")
- .field("pa", &format_args!("{:#010x}", self.pa.0))
- .field("va", &format_args!("{:#010x}", self.va.0))
- .field("size", &format_args!("{:#010x}", self.size))
- .finish()
- }
-}
-
pub enum RegimeVaRange {
Lower,
Upper,
@@ -572,7 +550,7 @@
region: VirtualRegion,
attributes: Attributes,
) -> Result<VirtualAddress, XlatError> {
- let blocks = Self::split_region_to_blocks(
+ let blocks = BlockIterator::new(
region.get_pa(),
region.base(),
region.length(),
@@ -590,7 +568,7 @@
/// # Arguments
/// * region: Memory region object
fn unmap_region(&mut self, region: &VirtualRegion) -> Result<(), XlatError> {
- let blocks = Self::split_region_to_blocks(
+ let blocks = BlockIterator::new(
region.get_pa(),
region.base(),
region.length(),
@@ -612,57 +590,6 @@
self.regions.find_containing_region(va, length).ok()
}
- /// Splits memory region to blocks that matches the granule size of the translation table.
- /// # Arguments
- /// * pa: Physical address
- /// * va: Virtual address
- /// * length: Region size in bytes
- /// * granule: Translation granule
- /// # Return value
- /// * Vector of granule sized blocks
- fn split_region_to_blocks(
- mut pa: PhysicalAddress,
- mut va: VirtualAddress,
- mut length: usize,
- granule: TranslationGranule<VA_BITS>,
- ) -> Result<Vec<Block>, XlatError> {
- let min_granule_mask = granule.block_size_at_level(3) - 1;
-
- if length == 0 {
- return Err(XlatError::InvalidParameterError(
- "Length cannot be 0".to_string(),
- ));
- }
-
- if (pa.0 | va.0 | length) & min_granule_mask != 0 {
- return Err(XlatError::InvalidParameterError(format!(
- "Addresses and length must be aligned {:#08x} {:#08x} {:#x} {:#x}",
- pa.0, va.0, length, min_granule_mask
- )));
- }
-
- let mut pages = Vec::new();
-
- while length > 0 {
- let initial_lookup_level = granule.initial_lookup_level();
-
- for block_size in
- (initial_lookup_level..=3).map(|level| granule.block_size_at_level(level))
- {
- if (pa.0 | va.0) & (block_size - 1) == 0 && length >= block_size {
- pages.push(Block::new(pa, va, block_size));
- pa = pa.add_offset(block_size).ok_or(XlatError::Overflow)?;
- va = va.add_offset(block_size).ok_or(XlatError::Overflow)?;
-
- length -= block_size;
- break;
- }
- }
- }
-
- Ok(pages)
- }
-
/// Add block to memory mapping
/// # Arguments
/// * block: Memory block that can be represented by a single translation table entry
@@ -991,49 +918,3 @@
}
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- type TestXlat = Xlat<36>;
-
- fn make_block(pa: usize, va: usize, size: usize) -> Block {
- Block::new(PhysicalAddress(pa), VirtualAddress(va), size)
- }
-
- #[test]
- fn test_split_to_pages() {
- let pages = TestXlat::split_region_to_blocks(
- PhysicalAddress(0x3fff_c000),
- VirtualAddress(0x3fff_c000),
- 0x4020_5000,
- TranslationGranule::Granule4k,
- )
- .unwrap();
- assert_eq!(make_block(0x3fff_c000, 0x3fff_c000, 0x1000), pages[0]);
- assert_eq!(make_block(0x3fff_d000, 0x3fff_d000, 0x1000), pages[1]);
- assert_eq!(make_block(0x3fff_e000, 0x3fff_e000, 0x1000), pages[2]);
- assert_eq!(make_block(0x3fff_f000, 0x3fff_f000, 0x1000), pages[3]);
- assert_eq!(make_block(0x4000_0000, 0x4000_0000, 0x4000_0000), pages[4]);
- assert_eq!(make_block(0x8000_0000, 0x8000_0000, 0x0020_0000), pages[5]);
- assert_eq!(make_block(0x8020_0000, 0x8020_0000, 0x1000), pages[6]);
- }
-
- #[test]
- fn test_split_to_pages_unaligned() {
- let pages = TestXlat::split_region_to_blocks(
- PhysicalAddress(0x3fff_c000),
- VirtualAddress(0x3f20_0000),
- 0x200000,
- TranslationGranule::Granule4k,
- )
- .unwrap();
- for (i, block) in pages.iter().enumerate().take(512) {
- assert_eq!(
- make_block(0x3fff_c000 + (i << 12), 0x3f20_0000 + (i << 12), 0x1000),
- *block
- );
- }
- }
-}