Files
RedBear-OS/src/syscall/driver.rs
T
Jeremy Soller 788526a3b3 Bare-bones ptracing functionality
Since even a very basic ptrace can be nice to have, I thought I would split
the, perhaps rather big, ptrace project up in multiple PRs to make as few
changes as necessary in each. This PR contains the initial registry modifying
bits and only a very basic security measure. Letting this out to the community
should be good for spotting bugs and maybe getting some hype ;)
2019-07-02 07:38:26 -06:00

146 lines
4.6 KiB
Rust

use crate::interrupt::syscall::SyscallStack;
use crate::memory::{allocate_frames, deallocate_frames, Frame};
use crate::paging::{ActivePageTable, PhysicalAddress, VirtualAddress};
use crate::paging::entry::EntryFlags;
use crate::context;
use crate::context::memory::Grant;
use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result};
use crate::syscall::flag::{PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE};
fn enforce_root() -> Result<()> {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
if context.euid == 0 {
Ok(())
} else {
Err(Error::new(EPERM))
}
}
pub fn iopl(level: usize, stack: &mut SyscallStack) -> Result<usize> {
enforce_root()?;
if level > 3 {
return Err(Error::new(EINVAL));
}
let iret = &mut stack.interrupt_stack.iret;
iret.rflags = (iret.rflags & !(3 << 12)) | ((level & 3) << 12);
Ok(0)
}
pub fn inner_physalloc(size: usize) -> Result<usize> {
allocate_frames((size + 4095)/4096).ok_or(Error::new(ENOMEM)).map(|frame| frame.start_address().get())
}
pub fn physalloc(size: usize) -> Result<usize> {
enforce_root()?;
inner_physalloc(size)
}
pub fn inner_physfree(physical_address: usize, size: usize) -> Result<usize> {
deallocate_frames(Frame::containing_address(PhysicalAddress::new(physical_address)), (size + 4095)/4096);
//TODO: Check that no double free occured
Ok(0)
}
pub fn physfree(physical_address: usize, size: usize) -> Result<usize> {
enforce_root()?;
inner_physfree(physical_address, size)
}
//TODO: verify exlusive access to physical memory
pub fn inner_physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
//TODO: Abstract with other grant creation
if size == 0 {
Ok(0)
} else {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut grants = context.grants.lock();
let from_address = (physical_address/4096) * 4096;
let offset = physical_address - from_address;
let full_size = ((offset + size + 4095)/4096) * 4096;
let mut to_address = crate::USER_GRANT_OFFSET;
let mut entry_flags = EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE;
if flags & PHYSMAP_WRITE == PHYSMAP_WRITE {
entry_flags |= EntryFlags::WRITABLE;
}
if flags & PHYSMAP_WRITE_COMBINE == PHYSMAP_WRITE_COMBINE {
entry_flags |= EntryFlags::HUGE_PAGE;
}
if flags & PHYSMAP_NO_CACHE == PHYSMAP_NO_CACHE {
entry_flags |= EntryFlags::NO_CACHE;
}
let mut i = 0;
while i < grants.len() {
let start = grants[i].start_address().get();
if to_address + full_size < start {
break;
}
let pages = (grants[i].size() + 4095) / 4096;
let end = start + pages * 4096;
to_address = end;
i += 1;
}
grants.insert(i, Grant::physmap(
PhysicalAddress::new(from_address),
VirtualAddress::new(to_address),
full_size,
entry_flags
));
Ok(to_address + offset)
}
}
pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
enforce_root()?;
inner_physmap(physical_address, size, flags)
}
pub fn inner_physunmap(virtual_address: usize) -> Result<usize> {
if virtual_address == 0 {
Ok(0)
} else {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut grants = context.grants.lock();
for i in 0 .. grants.len() {
let start = grants[i].start_address().get();
let end = start + grants[i].size();
if virtual_address >= start && virtual_address < end {
grants.remove(i).unmap();
return Ok(0);
}
}
Err(Error::new(EFAULT))
}
}
pub fn physunmap(virtual_address: usize) -> Result<usize> {
enforce_root()?;
inner_physunmap(virtual_address)
}
pub fn virttophys(virtual_address: usize) -> Result<usize> {
enforce_root()?;
let active_table = unsafe { ActivePageTable::new() };
match active_table.translate(VirtualAddress::new(virtual_address)) {
Some(physical_address) => Ok(physical_address.get()),
None => Err(Error::new(EFAULT))
}
}