fix: invalidate TLB on syscall CoW

This commit is contained in:
Mark Poliakov 2021-12-05 21:12:29 +02:00
parent b97db3a0c4
commit 2b160343b7
3 changed files with 34 additions and 17 deletions

View File

@ -4,10 +4,10 @@ use crate::arch::machine;
use crate::debug::Level;
use crate::dev::irq::{IntController, IrqContext};
use crate::mem;
use crate::proc::{sched, Thread};
use crate::proc::{sched, Process, Thread};
use crate::syscall;
use cortex_a::registers::{ESR_EL1, FAR_EL1};
use libsys::{abi::SystemCall, signal::Signal};
use libsys::{abi::SystemCall, signal::Signal, error::Errno};
use tock_registers::interfaces::Readable;
/// Trapped SIMD/FP functionality
@ -93,24 +93,21 @@ extern "C" fn __aa64_exc_sync_handler(exc: &mut ExceptionFrame) {
if iss & (1 << 6) != 0 && far < mem::KERNEL_OFFSET && sched::is_ready() {
let thread = Thread::current();
let proc = thread.owner().unwrap();
let asid = proc.asid();
if proc
.manipulate_space(|space| space.try_cow_copy(far))
.is_err()
{
let res = proc.manipulate_space(|space| {
space.try_cow_copy(far)?;
Process::invalidate_asid(asid);
Result::<(), Errno>::Ok(())
});
if res.is_err() {
// Kill program
errorln!("Data abort from {:#x}", exc.elr_el1);
dump_data_abort(Level::Error, esr, far as u64);
proc.enter_fault_signal(thread, Signal::SegmentationFault);
}
unsafe {
use cortex_a::registers::TTBR0_EL1;
let ttbr = TTBR0_EL1.get() as usize;
let asid = (ttbr >> 48) & 0xFF;
asm!("tlbi aside1, {}", in(reg) (asid << 48));
}
return;
}

View File

@ -8,7 +8,7 @@ use crate::mem::{
use crate::proc::{
wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED, Tid,
};
use crate::sync::IrqSafeSpinLock;
use crate::sync::{IrqSafeSpinLock};
use alloc::{rc::Rc, vec::Vec};
use core::sync::atomic::{AtomicU32, Ordering};
use libsys::{
@ -217,6 +217,7 @@ impl Process {
let space_phys = lock.space.as_mut().unwrap().address_phys();
let ttbr0 = space_phys | ((lock.id.asid() as usize) << 48);
debugln!("New user thread for {:?}, asid={:#x}", lock.id, lock.id.asid());
let thread = Thread::new_user(lock.id, entry, stack, arg, ttbr0)?;
let tid = thread.id();
@ -236,6 +237,7 @@ impl Process {
let dst_space = src_inner.space.as_mut().unwrap().fork()?;
let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET;
let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48);
debugln!("New TTBR0 for {:?}, asid={:#x}", dst_id, dst_id.asid());
let mut threads = Vec::new();
let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id();
@ -288,7 +290,7 @@ impl Process {
if let Some(space) = lock.space.take() {
unsafe {
Space::release(space);
asm!("tlbi aside1, {}", in(reg) ((lock.id.asid() as usize) << 48));
Process::invalidate_asid((lock.id.asid() as usize) << 48);
}
}
@ -460,6 +462,21 @@ impl Process {
Ok(base + offset)
}
pub fn asid(&self) -> usize {
(self.id().asid() as usize) << 48
}
pub fn invalidate_tlb(&self) {
Process::invalidate_asid(self.asid());
}
#[inline]
pub fn invalidate_asid(asid: usize) {
unsafe {
asm!("tlbi aside1, {}", in(reg) asid);
}
}
/// Loads a new program into current process address space
pub fn execve<F: FnOnce(&mut Space) -> Result<usize, Errno>>(
loader: F,
@ -525,7 +542,7 @@ impl Process {
// TODO drop old context
let ctx = thread.ctx.get();
let asid = (process_lock.id.asid() as usize) << 48;
asm!("tlbi aside1, {}", in(reg) asid);
Process::invalidate_asid(asid);
ctx.write(Context::user(
entry,

View File

@ -122,6 +122,7 @@ pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
}
let process = Process::current();
let asid = process.asid();
for i in (base / mem::PAGE_SIZE)..((base + len + mem::PAGE_SIZE - 1) / mem::PAGE_SIZE) {
if !is_el0_accessible(i * mem::PAGE_SIZE, write) {
@ -129,7 +130,9 @@ pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
// a write access
let res = if write {
process.manipulate_space(|space| {
space.try_cow_copy(i * mem::PAGE_SIZE)
space.try_cow_copy(i * mem::PAGE_SIZE)?;
Process::invalidate_asid(asid);
Ok(())
})
} else {
Err(Errno::DoesNotExist)