#![allow(clippy::too_many_lines)]
#![allow(clippy::cast_possible_truncation)]
use smmu::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== ARM SMMU v3 Basic Translation Example ===\n");
println!("Step 1: Creating SMMU instance...");
let smmu = SMMU::new();
println!(" ✓ SMMU created (version: {SMMU_IMPL_VERSION})\n");
println!("Step 2: Configuring stream...");
let stream_id = StreamID::new(42)?;
let stream_config = StreamConfig::builder()
.translation_enabled(true)
.stage1_enabled(true)
.pasid_enabled(true)
.max_pasid(256)
.build()?;
smmu.configure_stream(stream_id, stream_config)?;
println!(" ✓ Stream {} configured for Stage-1 translation\n", stream_id.as_u32());
println!("Step 3: Creating PASID...");
let pasid = PASID::new(0)?;
smmu.create_pasid(stream_id, pasid)?;
println!(" ✓ PASID {} created for stream {}\n", pasid.as_u32(), stream_id.as_u32());
println!("Step 4: Mapping pages...");
let iova1 = IOVA::new(0x1000)?;
let pa1 = PA::new(0x1_0000)?;
smmu.map_page(
stream_id,
pasid,
iova1,
pa1,
PagePermissions::read_write(),
SecurityState::NonSecure,
)?;
println!(" ✓ Mapped IOVA 0x{:04x} -> PA 0x{:05x} (RW)", iova1.as_u64(), pa1.as_u64());
let iova2 = IOVA::new(0x2000)?;
let pa2 = PA::new(0x2_0000)?;
smmu.map_page(
stream_id,
pasid,
iova2,
pa2,
PagePermissions::read_only(),
SecurityState::NonSecure,
)?;
println!(" ✓ Mapped IOVA 0x{:04x} -> PA 0x{:05x} (RO)\n", iova2.as_u64(), pa2.as_u64());
println!("Step 5: Performing translations...");
let result1 = smmu.translate(stream_id, pasid, iova1, AccessType::Read, SecurityState::NonSecure)?;
println!(
" ✓ Translate IOVA 0x{:04x} -> PA 0x{:05x} (Read)",
iova1.as_u64(),
result1.physical_address().as_u64()
);
assert_eq!(result1.physical_address().as_u64(), pa1.as_u64());
let result2 = smmu.translate(stream_id, pasid, iova1, AccessType::Write, SecurityState::NonSecure)?;
println!(
" ✓ Translate IOVA 0x{:04x} -> PA 0x{:05x} (Write)",
iova1.as_u64(),
result2.physical_address().as_u64()
);
assert_eq!(result2.physical_address().as_u64(), pa1.as_u64());
let result3 = smmu.translate(stream_id, pasid, iova2, AccessType::Read, SecurityState::NonSecure)?;
println!(
" ✓ Translate IOVA 0x{:04x} -> PA 0x{:05x} (Read)",
iova2.as_u64(),
result3.physical_address().as_u64()
);
assert_eq!(result3.physical_address().as_u64(), pa2.as_u64());
println!("\nStep 6: Demonstrating permission fault...");
match smmu.translate(stream_id, pasid, iova2, AccessType::Write, SecurityState::NonSecure) {
Ok(_) => println!(" ✗ ERROR: Write to read-only page should have failed!"),
Err(TranslationError::PermissionViolation { access }) => {
println!(" ✓ Permission fault detected as expected:");
println!(" Access type: {access:?}");
println!(" Address: 0x{:x}", iova2.as_u64());
},
Err(e) => println!(" ✗ Unexpected error: {e}"),
}
println!("\nStep 7: Demonstrating translation fault...");
let unmapped_iova = IOVA::new(0x5000)?;
match smmu.translate(stream_id, pasid, unmapped_iova, AccessType::Read, SecurityState::NonSecure) {
Ok(_) => println!(" ✗ ERROR: Unmapped address should have failed!"),
Err(TranslationError::PageNotMapped) => {
println!(" ✓ Translation fault detected as expected:");
println!(" Error: Page not mapped");
println!(" Address: 0x{:x}", unmapped_iova.as_u64());
},
Err(e) => println!(" ✗ Unexpected error: {e}"),
}
println!("\n=== Example completed successfully! ===");
Ok(())
}