#![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 Multi-Stream Management Example ===\n");
println!("Creating SMMU instance with capacity for multiple streams...");
let smmu = SMMU::new();
println!(" ✓ SMMU created\n");
println!("Configuring Device 1 (Network Card)...");
let net_stream = StreamID::new(10)?;
let net_config = StreamConfig::builder()
.translation_enabled(true)
.stage1_enabled(true)
.pasid_enabled(false) .build()?;
smmu.configure_stream(net_stream, net_config)?;
let net_pasid = PASID::new(0)?;
smmu.create_pasid(net_stream, net_pasid)?;
let net_iova = IOVA::new(0x1_0000)?;
let net_pa = PA::new(0x10_0000)?;
smmu.map_page(
net_stream,
net_pasid,
net_iova,
net_pa,
PagePermissions::read_write(),
SecurityState::NonSecure,
)?;
println!(" ✓ Network card configured (Stream ID: {})", net_stream.as_u32());
println!(" Mapped IOVA 0x{:x} -> PA 0x{:x}\n", net_iova.as_u64(), net_pa.as_u64());
println!("Configuring Device 2 (GPU)...");
let gpu_stream = StreamID::new(20)?;
let gpu_config = StreamConfig::builder()
.translation_enabled(true)
.stage1_enabled(true)
.pasid_enabled(true) .max_pasid(256)
.build()?;
smmu.configure_stream(gpu_stream, gpu_config)?;
let gpu_pasid1 = PASID::new(1)?;
let gpu_pasid2 = PASID::new(2)?;
smmu.create_pasid(gpu_stream, gpu_pasid1)?;
smmu.create_pasid(gpu_stream, gpu_pasid2)?;
let gpu_iova = IOVA::new(0x2_0000)?;
let gpu_pa1 = PA::new(0x20_0000)?;
let gpu_pa2 = PA::new(0x30_0000)?;
smmu.map_page(
gpu_stream,
gpu_pasid1,
gpu_iova,
gpu_pa1,
PagePermissions::read_write(),
SecurityState::NonSecure,
)?;
smmu.map_page(
gpu_stream,
gpu_pasid2,
gpu_iova,
gpu_pa2,
PagePermissions::read_write(),
SecurityState::NonSecure,
)?;
println!(" ✓ GPU configured (Stream ID: {})", gpu_stream.as_u32());
println!(" PASID 1: IOVA 0x{:x} -> PA 0x{:x}", gpu_iova.as_u64(), gpu_pa1.as_u64());
println!(" PASID 2: IOVA 0x{:x} -> PA 0x{:x}\n", gpu_iova.as_u64(), gpu_pa2.as_u64());
println!("Configuring Device 3 (Storage Controller)...");
let storage_stream = StreamID::new(30)?;
let storage_config = StreamConfig::bypass();
smmu.configure_stream(storage_stream, storage_config)?;
println!(
" ✓ Storage controller configured (Stream ID: {}, Bypass mode)\n",
storage_stream.as_u32()
);
println!("Demonstrating stream independence...\n");
println!("Network Card Translation:");
let net_result = smmu.translate(net_stream, net_pasid, net_iova, AccessType::Read, SecurityState::NonSecure)?;
println!(
" Stream {}: IOVA 0x{:x} -> PA 0x{:x}",
net_stream.as_u32(),
net_iova.as_u64(),
net_result.physical_address().as_u64()
);
assert_eq!(net_result.physical_address().as_u64(), net_pa.as_u64());
println!("\nGPU Translations:");
let gpu_result1 = smmu.translate(gpu_stream, gpu_pasid1, gpu_iova, AccessType::Read, SecurityState::NonSecure)?;
println!(
" Stream {}, PASID {}: IOVA 0x{:x} -> PA 0x{:x}",
gpu_stream.as_u32(),
gpu_pasid1.as_u32(),
gpu_iova.as_u64(),
gpu_result1.physical_address().as_u64()
);
assert_eq!(gpu_result1.physical_address().as_u64(), gpu_pa1.as_u64());
let gpu_result2 = smmu.translate(gpu_stream, gpu_pasid2, gpu_iova, AccessType::Read, SecurityState::NonSecure)?;
println!(
" Stream {}, PASID {}: IOVA 0x{:x} -> PA 0x{:x}",
gpu_stream.as_u32(),
gpu_pasid2.as_u32(),
gpu_iova.as_u64(),
gpu_result2.physical_address().as_u64()
);
assert_eq!(gpu_result2.physical_address().as_u64(), gpu_pa2.as_u64());
println!("\nStorage Controller Translation (Bypass):");
let storage_pasid = PASID::new(0)?;
let storage_iova = IOVA::new(0x50_0000)?;
let storage_result = smmu.translate(storage_stream, storage_pasid, storage_iova, AccessType::Read, SecurityState::NonSecure)?;
println!(
" Stream {}: IOVA 0x{:x} -> PA 0x{:x} (identity mapping)",
storage_stream.as_u32(),
storage_iova.as_u64(),
storage_result.physical_address().as_u64()
);
assert_eq!(storage_result.physical_address().as_u64(), storage_iova.as_u64());
println!("\nDemonstrating stream isolation:");
let gpu_iova_via_net = smmu.translate(net_stream, net_pasid, gpu_iova, AccessType::Read, SecurityState::NonSecure);
match gpu_iova_via_net {
Ok(_) => println!(" ✗ ERROR: Should not be able to access GPU memory from network stream!"),
Err(TranslationError::PageNotMapped) => {
println!(" ✓ Stream isolation verified: Network stream cannot access unmapped GPU address");
},
Err(e) => println!(" Unexpected error: {e}"),
}
println!("\n=== Stream Configuration Summary ===");
println!("Stream {}: Network card - Stage-1 enabled, no PASID", net_stream.as_u32());
println!(
"Stream {}: GPU - Stage-1 enabled, PASID support (2 contexts)",
gpu_stream.as_u32()
);
println!("Stream {}: Storage - Bypass mode (identity mapping)", storage_stream.as_u32());
println!("\n=== Example completed successfully! ===");
Ok(())
}