mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
kernel: implement UpdateMemoryFlags syscall
This call is used to strip flags from a chunk of memory. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
3380a0e0ed
commit
5fddf7c230
4 changed files with 182 additions and 1 deletions
|
|
@ -111,3 +111,11 @@ pub fn hand_page_to_user(_virt: *mut u8) -> Result<(), Error> {
|
|||
pub fn virt_to_phys(virt: usize) -> Result<usize, Error> {
|
||||
Ok(virt)
|
||||
}
|
||||
|
||||
pub fn page_flags(_virt: usize) -> Option<MemoryFlags> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn update_page_flags(_virt: usize, _flags: MemoryFlags) -> Result<(), xous_kernel::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -282,7 +282,7 @@ pub fn hand_page_to_user(virt: *mut u8) -> Result<(), xous_kernel::Error> {
|
|||
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||
// address space at this address.
|
||||
let l1_pt = unsafe { &mut (*(PAGE_TABLE_ROOT_OFFSET as *mut RootPageTable)) };
|
||||
let l1_pt =&mut l1_pt.entries;
|
||||
let l1_pt = &mut l1_pt.entries;
|
||||
|
||||
// Subsequent pagetables are defined as being mapped starting at
|
||||
// PAGE_TABLE_OFFSET
|
||||
|
|
@ -789,3 +789,124 @@ pub fn address_available(virt: usize) -> bool {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the `MemoryFlags` for the requested virtual address. The address must
|
||||
/// be valid and page-aligned, and must not be Shared.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * **None**: The page is not valid or is shared
|
||||
/// * **Some(MemoryFlags)**: The translated sharing permissions of the given flags
|
||||
pub fn page_flags(virt: usize) -> Option<MemoryFlags> {
|
||||
let vpn1 = (virt >> 22) & ((1 << 10) - 1);
|
||||
let vpn0 = (virt >> 12) & ((1 << 10) - 1);
|
||||
|
||||
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||
// address space at this address.
|
||||
let l1_pt = unsafe { &mut (*(PAGE_TABLE_ROOT_OFFSET as *mut RootPageTable)) };
|
||||
let l1_pt = &mut l1_pt.entries;
|
||||
|
||||
// Subsequent pagetables are defined as being mapped starting at
|
||||
// offset 0x0020_0004, so 4 must be added to the ppn1 value.
|
||||
let l0pt_virt = PAGE_TABLE_OFFSET + vpn1 * PAGE_SIZE;
|
||||
let l0_pt = &mut unsafe { &mut (*(l0pt_virt as *mut LeafPageTable)) };
|
||||
|
||||
// If the level 1 pagetable doesn't exist, then this address is invalid
|
||||
if l1_pt[vpn1] & MMUFlags::VALID.bits() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mmu_flags = l0_pt.entries[vpn0];
|
||||
|
||||
// If the page is "Valid" but shared, issue a sharing violation
|
||||
if mmu_flags & MMUFlags::S.bits() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut return_flags = MemoryFlags::empty();
|
||||
|
||||
if mmu_flags & MMUFlags::R.bits() != 0 {
|
||||
return_flags = return_flags | MemoryFlags::R;
|
||||
}
|
||||
|
||||
if mmu_flags & MMUFlags::W.bits() != 0 {
|
||||
return_flags = return_flags | MemoryFlags::W;
|
||||
}
|
||||
|
||||
if mmu_flags & MMUFlags::X.bits() != 0 {
|
||||
return_flags = return_flags | MemoryFlags::X;
|
||||
}
|
||||
|
||||
if return_flags.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(return_flags)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_page_flags(virt: usize, flags: MemoryFlags) -> Result<(), xous_kernel::Error> {
|
||||
// The resulting flags must actually be valid
|
||||
if (flags & (MemoryFlags::R | MemoryFlags::W | MemoryFlags::X)).is_empty() {
|
||||
return Err(xous_kernel::Error::MemoryInUse);
|
||||
}
|
||||
|
||||
let vpn1 = (virt >> 22) & ((1 << 10) - 1);
|
||||
let vpn0 = (virt >> 12) & ((1 << 10) - 1);
|
||||
|
||||
// The root (l1) pagetable is defined to be mapped into our virtual
|
||||
// address space at this address.
|
||||
let l1_pt = unsafe { &mut (*(PAGE_TABLE_ROOT_OFFSET as *mut RootPageTable)) };
|
||||
let l1_pt = &mut l1_pt.entries;
|
||||
|
||||
// Subsequent pagetables are defined as being mapped starting at
|
||||
// offset 0x0020_0004, so 4 must be added to the ppn1 value.
|
||||
let l0pt_virt = PAGE_TABLE_OFFSET + vpn1 * PAGE_SIZE;
|
||||
let l0_pt = &mut unsafe { &mut (*(l0pt_virt as *mut LeafPageTable)) };
|
||||
|
||||
// If the level 1 pagetable doesn't exist, then this address is invalid
|
||||
if l1_pt[vpn1] & MMUFlags::VALID.bits() == 0 {
|
||||
return Err(xous_kernel::Error::OutOfMemory);
|
||||
}
|
||||
|
||||
let mut mmu_flags = l0_pt.entries[vpn0];
|
||||
|
||||
// If the page is "Valid" but shared, issue a sharing violation
|
||||
if mmu_flags & MMUFlags::S.bits() != 0 {
|
||||
return Err(xous_kernel::Error::ShareViolation);
|
||||
}
|
||||
|
||||
// Strip the flags as requested
|
||||
if (flags & MemoryFlags::X).is_empty() {
|
||||
if mmu_flags & MMUFlags::X.bits() != 0 {
|
||||
mmu_flags = mmu_flags & !MMUFlags::X.bits();
|
||||
}
|
||||
} else if mmu_flags & MMUFlags::X.bits() == 0 {
|
||||
// Ensure we're not adding flags back
|
||||
return Err(xous_kernel::Error::ShareViolation);
|
||||
}
|
||||
|
||||
// Strip the flags as requested
|
||||
if (flags & MemoryFlags::R).is_empty() {
|
||||
if mmu_flags & MMUFlags::R.bits() != 0 {
|
||||
mmu_flags = mmu_flags & !MMUFlags::R.bits();
|
||||
}
|
||||
} else if mmu_flags & MMUFlags::R.bits() == 0 {
|
||||
// Ensure we're not adding flags back
|
||||
return Err(xous_kernel::Error::ShareViolation);
|
||||
}
|
||||
|
||||
// Strip the flags as requested
|
||||
if (flags & MemoryFlags::W).is_empty() {
|
||||
if mmu_flags & MMUFlags::W.bits() != 0 {
|
||||
mmu_flags = mmu_flags & !MMUFlags::W.bits();
|
||||
}
|
||||
} else if mmu_flags & MMUFlags::W.bits() == 0 {
|
||||
// Ensure we're not adding flags back
|
||||
return Err(xous_kernel::Error::ShareViolation);
|
||||
}
|
||||
|
||||
// Update the MMU
|
||||
l0_pt.entries[vpn0] = mmu_flags;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -776,4 +776,47 @@ impl MemoryManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjust the flags on the given memory range. This allows for stripping flags from a memory
|
||||
/// range but does not allow adding flags. The memory range must exist, and the flags must be valid.
|
||||
pub fn update_memory_flags(
|
||||
&mut self,
|
||||
range: MemoryRange,
|
||||
flags: MemoryFlags,
|
||||
) -> Result<(), xous_kernel::Error> {
|
||||
let virt = range.as_mut_ptr() as usize;
|
||||
let size = range.len();
|
||||
if virt & (PAGE_SIZE - 1) != 0 {
|
||||
return Err(xous_kernel::Error::BadAlignment);
|
||||
}
|
||||
|
||||
if size & (PAGE_SIZE - 1) != 0 {
|
||||
return Err(xous_kernel::Error::BadAlignment);
|
||||
}
|
||||
|
||||
// Pre-check the range to ensure the new flags are valid
|
||||
for virt in (virt..(virt + size)).step_by(PAGE_SIZE) {
|
||||
let existing_flags =
|
||||
crate::arch::mem::page_flags(virt).ok_or(xous_kernel::Error::MemoryInUse)?;
|
||||
// If the new flags add to the range, return an error.
|
||||
if !(!existing_flags & flags).is_empty() {
|
||||
return Err(xous_kernel::Error::MemoryInUse);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the flags are validated, perform the update. This is fine as long as
|
||||
// we're unicore.
|
||||
for virt in (virt..(virt + size)).step_by(PAGE_SIZE) {
|
||||
let existing_flags =
|
||||
crate::arch::mem::page_flags(virt).ok_or(xous_kernel::Error::MemoryInUse)?;
|
||||
// If the new flags add to the range, return an error.
|
||||
if !(!existing_flags & flags).is_empty() {
|
||||
return Err(xous_kernel::Error::MemoryInUse);
|
||||
}
|
||||
|
||||
crate::arch::mem::update_page_flags(virt, flags)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -884,6 +884,15 @@ pub fn handle_inner(pid: PID, tid: TID, in_irq: bool, call: SysCall) -> SysCallR
|
|||
ret
|
||||
})
|
||||
}
|
||||
SysCall::UpdateMemoryFlags(range, flags, pid) => {
|
||||
// We do not yet support modifying flags for other processes.
|
||||
if pid.is_some() {
|
||||
return Err(xous_kernel::Error::ProcessNotChild);
|
||||
}
|
||||
|
||||
MemoryManager::with_mut(|mm| mm.update_memory_flags(range, flags))?;
|
||||
Ok(xous_kernel::Result::Ok)
|
||||
}
|
||||
/* https://github.com/betrusted-io/xous-core/issues/90
|
||||
SysCall::SetExceptionHandler(pc, sp) => SystemServices::with_mut(|ss| {
|
||||
ss.set_exception_handler(pid, pc, sp)
|
||||
|
|
|
|||
Loading…
Reference in a new issue