Skip to content

Commit 59b0af5

Browse files
Merge pull request #32 from emanuelemessina/mpu-reconfigure
Reconfigure pmsav8 EL1 MPU regions at runtime
2 parents 6a8aefe + c29258b commit 59b0af5

File tree

1 file changed

+91
-73
lines changed

1 file changed

+91
-73
lines changed

cortex-ar/src/pmsav8.rs

Lines changed: 91 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -63,94 +63,112 @@ impl El1Mpu {
6363
})
6464
}
6565

66-
/// Configure the EL1 MPU
67-
pub fn configure(&mut self, config: &Config) -> Result<(), Error> {
68-
if config.regions.len() > self.num_regions() as usize {
66+
/// Write a single region to the EL1 MPU
67+
///
68+
/// ## Arguments
69+
///
70+
/// - `region`: The [Region] object containing the configuration for the MPU region.
71+
/// - `idx`: The index of the region to be configured.
72+
///
73+
/// ## Errors
74+
///
75+
/// Returns:
76+
/// - [Error::UnalignedRegion] if the region's start address is not 64-byte aligned.
77+
/// - [Error::UnalignedRegion] if the region's end address is not 63-byte aligned.
78+
/// - [Error::InvalidMair] if the region's MAIR index is invalid (greater than 7).
79+
pub fn set_region(&mut self, idx: u8, region: &Region) -> Result<(), Error> {
80+
let start = *(region.range.start()) as usize as u32;
81+
// Check for 64-byte alignment (0x3F is six bits)
82+
if start & 0x3F != 0 {
83+
return Err(Error::UnalignedRegion(region.range.clone()));
84+
}
85+
let end = *(region.range.end()) as usize as u32;
86+
if end & 0x3F != 0x3F {
87+
return Err(Error::UnalignedRegion(region.range.clone()));
88+
}
89+
if region.mair > 7 {
90+
return Err(Error::InvalidMair(region.mair));
91+
}
92+
register::Prselr::write(register::Prselr(idx as u32));
93+
register::Prbar::write({
94+
let mut bar = register::Prbar::new_with_raw_value(0);
95+
bar.set_base(u26::from_u32(start >> 6));
96+
bar.set_access_perms(region.access);
97+
bar.set_nx(region.no_exec);
98+
bar.set_shareability(region.shareability);
99+
bar
100+
});
101+
register::Prlar::write({
102+
let mut lar = register::Prlar::new_with_raw_value(0);
103+
lar.set_limit(u26::from_u32(end >> 6));
104+
lar.set_enabled(region.enable);
105+
lar.set_mair(u3::from_u8(region.mair));
106+
lar
107+
});
108+
109+
Ok(())
110+
}
111+
112+
/// Writes a subset of EL1 MPU regions starting from a specified index.
113+
///
114+
/// ## Arguments
115+
///
116+
/// - `regions_starting_idx`: The starting index for the regions to be reconfigured.
117+
/// - `regions`: A slice of [Region] objects that will overwrite the previous regions starting from `regions_starting_idx`.
118+
pub fn set_regions(
119+
&mut self,
120+
regions_starting_idx: u8,
121+
regions: &[Region],
122+
) -> Result<(), Error> {
123+
if regions.len().saturating_add(regions_starting_idx as usize) > self.num_regions() as usize
124+
{
69125
return Err(Error::TooManyRegions);
70126
}
71-
for (idx, region) in config.regions.iter().enumerate() {
72-
let start = *(region.range.start()) as usize as u32;
73-
// Check for 64-byte alignment (0x3F is six bits)
74-
if start & 0x3F != 0 {
75-
return Err(Error::UnalignedRegion(region.range.clone()));
76-
}
77-
let end = *(region.range.end()) as usize as u32;
78-
if end & 0x3F != 0x3F {
79-
return Err(Error::UnalignedRegion(region.range.clone()));
80-
}
81-
if region.mair > 7 {
82-
return Err(Error::InvalidMair(region.mair));
83-
}
84-
register::Prselr::write(register::Prselr(idx as u32));
85-
register::Prbar::write({
86-
let mut bar = register::Prbar::new_with_raw_value(0);
87-
bar.set_base(u26::from_u32(start >> 6));
88-
bar.set_access_perms(region.access);
89-
bar.set_nx(region.no_exec);
90-
bar.set_shareability(region.shareability);
91-
bar
92-
});
93-
register::Prlar::write({
94-
let mut lar = register::Prlar::new_with_raw_value(0);
95-
lar.set_limit(u26::from_u32(end >> 6));
96-
lar.set_enabled(region.enable);
97-
lar.set_mair(u3::from_u8(region.mair));
98-
lar
99-
});
127+
128+
for (idx, region) in regions.iter().enumerate() {
129+
self.set_region(idx as u8 + regions_starting_idx, region)?;
100130
}
101131

102-
let mem_attr0 = config
103-
.memory_attributes
104-
.get(0)
105-
.map(|m| m.to_bits())
106-
.unwrap_or(0) as u32;
107-
let mem_attr1 = config
108-
.memory_attributes
109-
.get(1)
110-
.map(|m| m.to_bits())
111-
.unwrap_or(0) as u32;
112-
let mem_attr2 = config
113-
.memory_attributes
114-
.get(2)
115-
.map(|m| m.to_bits())
116-
.unwrap_or(0) as u32;
117-
let mem_attr3 = config
118-
.memory_attributes
119-
.get(3)
120-
.map(|m| m.to_bits())
121-
.unwrap_or(0) as u32;
132+
Ok(())
133+
}
134+
135+
/// Set the memory attributes to MAIR0 and MAIR1
136+
pub fn set_attributes(&mut self, memattrs: &[MemAttr]) {
137+
let mem_attr0 = memattrs.get(0).map(|m| m.to_bits()).unwrap_or(0) as u32;
138+
let mem_attr1 = memattrs.get(1).map(|m| m.to_bits()).unwrap_or(0) as u32;
139+
let mem_attr2 = memattrs.get(2).map(|m| m.to_bits()).unwrap_or(0) as u32;
140+
let mem_attr3 = memattrs.get(3).map(|m| m.to_bits()).unwrap_or(0) as u32;
122141
let mair0 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0;
123142
unsafe {
124143
register::Mair0::write(register::Mair0(mair0));
125144
}
126-
let mem_attr0 = config
127-
.memory_attributes
128-
.get(4)
129-
.map(|m| m.to_bits())
130-
.unwrap_or(0) as u32;
131-
let mem_attr1 = config
132-
.memory_attributes
133-
.get(5)
134-
.map(|m| m.to_bits())
135-
.unwrap_or(0) as u32;
136-
let mem_attr2 = config
137-
.memory_attributes
138-
.get(6)
139-
.map(|m| m.to_bits())
140-
.unwrap_or(0) as u32;
141-
let mem_attr3 = config
142-
.memory_attributes
143-
.get(7)
144-
.map(|m| m.to_bits())
145-
.unwrap_or(0) as u32;
145+
let mem_attr0 = memattrs.get(4).map(|m| m.to_bits()).unwrap_or(0) as u32;
146+
let mem_attr1 = memattrs.get(5).map(|m| m.to_bits()).unwrap_or(0) as u32;
147+
let mem_attr2 = memattrs.get(6).map(|m| m.to_bits()).unwrap_or(0) as u32;
148+
let mem_attr3 = memattrs.get(7).map(|m| m.to_bits()).unwrap_or(0) as u32;
146149
let mair1 = mem_attr3 << 24 | mem_attr2 << 16 | mem_attr1 << 8 | mem_attr0;
147150
unsafe {
148151
register::Mair1::write(register::Mair1(mair1));
149152
}
153+
}
150154

155+
/// Enable or disable the background region
156+
pub fn background_region_enable(&mut self, enable: bool) {
151157
register::Sctlr::modify(|r| {
152-
r.set_br(config.background_config);
158+
r.set_br(enable);
153159
});
160+
}
161+
162+
/// Configure the EL1 MPU
163+
///
164+
/// Write regions, attributes and enable/disable the background region with a single [Config] struct.
165+
pub fn configure(&mut self, config: &Config) -> Result<(), Error> {
166+
self.set_regions(0, config.regions)?;
167+
168+
self.set_attributes(config.memory_attributes);
169+
170+
self.background_region_enable(config.background_config);
171+
154172
Ok(())
155173
}
156174

0 commit comments

Comments
 (0)