Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions etc/syscalls_linux_aarch64.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
| 0x72 (114) | clock_getres | (const clockid_t which_clock, struct __kernel_timespec *tp) | __arm64_sys_clock_getres | false |
| 0x73 (115) | clock_nanosleep | (const clockid_t which_clock, int flags, const struct __kernel_timespec *rqtp, struct __kernel_timespec *rmtp) | __arm64_sys_clock_nanosleep | false |
| 0x74 (116) | syslog | (int type, char *buf, int len) | __arm64_sys_syslog | false |
| 0x75 (117) | ptrace | (long request, long pid, unsigned long addr, unsigned long data) | __arm64_sys_ptrace | false |
| 0x75 (117) | ptrace | (long request, long pid, unsigned long addr, unsigned long data) | __arm64_sys_ptrace | partially |
| 0x76 (118) | sched_setparam | (pid_t pid, struct sched_param *param) | __arm64_sys_sched_setparam | false |
| 0x77 (119) | sched_setscheduler | (pid_t pid, int policy, struct sched_param *param) | __arm64_sys_sched_setscheduler | false |
| 0x78 (120) | sched_getscheduler | (pid_t pid) | __arm64_sys_sched_getscheduler | false |
Expand Down Expand Up @@ -254,7 +254,7 @@
| 0x10b (267) | syncfs | (int fd) | __arm64_sys_syncfs | true |
| 0x10c (268) | setns | (int fd, int flags) | __arm64_sys_setns | false |
| 0x10d (269) | sendmmsg | (int fd, struct mmsghdr *mmsg, unsigned int vlen, unsigned int flags) | __arm64_sys_sendmmsg | false |
| 0x10e (270) | process_vm_readv | (pid_t pid, const struct iovec *lvec, unsigned long liovcnt, const struct iovec *rvec, unsigned long riovcnt, unsigned long flags) | __arm64_sys_process_vm_readv | false |
| 0x10e (270) | process_vm_readv | (pid_t pid, const struct iovec *lvec, unsigned long liovcnt, const struct iovec *rvec, unsigned long riovcnt, unsigned long flags) | __arm64_sys_process_vm_readv | true |
| 0x10f (271) | process_vm_writev | (pid_t pid, const struct iovec *lvec, unsigned long liovcnt, const struct iovec *rvec, unsigned long riovcnt, unsigned long flags) | __arm64_sys_process_vm_writev | false |
| 0x110 (272) | kcmp | (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) | __arm64_sys_kcmp | false |
| 0x111 (273) | finit_module | (int fd, const char *uargs, int flags) | __arm64_sys_finit_module | false |
Expand Down
3 changes: 3 additions & 0 deletions libkernel/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ pub enum KernelError {
#[error("No such process")]
NoProcess,

#[error("No child process")]
NoChildProcess,

#[error("Operation timed out")]
TimedOut,

Expand Down
1 change: 1 addition & 0 deletions libkernel/src/error/syscall_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub fn kern_err_to_syscall(err: KernelError) -> isize {
KernelError::NotSupported => ENOSYS,
KernelError::NoMemory => ENOMEM,
KernelError::TimedOut => ETIMEDOUT,
KernelError::NoChildProcess => ECHILD,
e => todo!("{e}"),
}
}
50 changes: 48 additions & 2 deletions src/arch/arm64/exceptions/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ use crate::{
memory::{
brk::sys_brk,
mmap::{sys_mmap, sys_mprotect, sys_munmap},
process_vm::sys_process_vm_readv,
},
process::{
TaskState,
caps::{sys_capget, sys_capset},
clone::sys_clone,
creds::{
Expand All @@ -54,6 +56,7 @@ use crate::{
select::{sys_ppoll, sys_pselect6},
},
prctl::sys_prctl,
ptrace::{TracePoint, ptrace_stop, sys_ptrace},
sleep::sys_nanosleep,
thread_group::{
Pgid,
Expand All @@ -79,6 +82,8 @@ use libkernel::{
};

pub async fn handle_syscall() {
ptrace_stop(TracePoint::SyscallEntry).await;

let (nr, arg1, arg2, arg3, arg4, arg5, arg6) = {
let mut task = current_task();

Expand Down Expand Up @@ -274,8 +279,28 @@ pub async fn handle_syscall() {
}
0x5a => sys_capget(TUA::from_value(arg1 as _), TUA::from_value(arg2 as _)).await,
0x5b => sys_capset(TUA::from_value(arg1 as _), TUA::from_value(arg2 as _)).await,
0x5d => sys_exit(arg1 as _).await,
0x5e => sys_exit_group(arg1 as _),
0x5d => {
let _ = sys_exit(arg1 as _).await;

debug_assert!(matches!(
*current_task().state.lock_save_irq(),
TaskState::Finished
));

// Don't process result on exit.
return;
}
0x5e => {
let _ = sys_exit_group(arg1 as _).await;

debug_assert!(matches!(
*current_task().state.lock_save_irq(),
TaskState::Finished
));

// Don't process result on exit.
return;
}
0x60 => sys_set_tid_address(TUA::from_value(arg1 as _)),
0x62 => {
sys_futex(
Expand All @@ -291,6 +316,15 @@ pub async fn handle_syscall() {
0x63 => sys_set_robust_list(TUA::from_value(arg1 as _), arg2 as _).await,
0x65 => sys_nanosleep(TUA::from_value(arg1 as _), TUA::from_value(arg2 as _)).await,
0x71 => sys_clock_gettime(arg1 as _, TUA::from_value(arg2 as _)).await,
0x75 => {
sys_ptrace(
arg1 as _,
arg2 as _,
TUA::from_value(arg3 as _),
TUA::from_value(arg4 as _),
)
.await
}
0x7b => Err(KernelError::NotSupported),
0x7c => sys_sched_yield(),
0x81 => sys_kill(arg1 as _, arg2.into()),
Expand Down Expand Up @@ -402,6 +436,17 @@ pub async fn handle_syscall() {
.await
}
0x10b => sys_syncfs(arg1.into()).await,
0x10e => {
sys_process_vm_readv(
arg1 as _,
TUA::from_value(arg2 as _),
arg3 as _,
TUA::from_value(arg4 as _),
arg5 as _,
arg6 as _,
)
.await
}
0x114 => {
sys_renameat2(
arg1.into(),
Expand Down Expand Up @@ -466,4 +511,5 @@ pub async fn handle_syscall() {
};

current_task().ctx.user_mut().x[0] = ret_val.cast_unsigned() as u64;
ptrace_stop(TracePoint::SyscallExit).await;
}
7 changes: 5 additions & 2 deletions src/arch/arm64/memory/fault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,14 @@ fn run_mem_fault_handler(exception: Exception, info: AbortIss) -> Result<FaultRe
let fault_addr = VA::from_value(far as usize);

let task = current_task();
let mut vm = task.vm.lock_save_irq();

match info.ifsc.category() {
IfscCategory::TranslationFault => handle_demand_fault(&mut vm, fault_addr, access_kind),
IfscCategory::TranslationFault => {
handle_demand_fault(task.vm.clone(), fault_addr, access_kind)
}
IfscCategory::PermissionFault => {
let mut vm = task.vm.lock_save_irq();

let pg_info = vm
.mm_mut()
.address_space_mut()
Expand Down
3 changes: 3 additions & 0 deletions src/arch/arm64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use memory::{
mmu::{Arm64KernelAddressSpace, KERN_ADDR_SPC},
uaccess::{Arm64CopyFromUser, Arm64CopyStrnFromUser, Arm64CopyToUser, try_copy_from_user},
};
use ptrace::Arm64PtraceGPRegs;

use crate::{
process::{
Expand All @@ -36,6 +37,7 @@ mod fdt;
mod memory;
mod proc;
pub mod psci;
pub mod ptrace;

pub struct Aarch64 {}

Expand Down Expand Up @@ -77,6 +79,7 @@ impl VirtualMemory for Aarch64 {

impl Arch for Aarch64 {
type UserContext = ExceptionState;
type PTraceGpRegs = Arm64PtraceGPRegs;

fn new_user_context(entry_point: VA, stack_top: VA) -> Self::UserContext {
ExceptionState {
Expand Down
25 changes: 25 additions & 0 deletions src/arch/arm64/ptrace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::memory::uaccess::UserCopyable;

use super::exceptions::ExceptionState;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Arm64PtraceGPRegs {
pub x: [u64; 31], // x0-x30
pub sp: u64,
pub pc: u64,
pub pstate: u64,
}

unsafe impl UserCopyable for Arm64PtraceGPRegs {}

impl From<&ExceptionState> for Arm64PtraceGPRegs {
fn from(value: &ExceptionState) -> Self {
Self {
x: value.x,
sp: value.sp_el0,
pc: value.elr_el1,
pstate: value.spsr_el1,
}
}
}
14 changes: 10 additions & 4 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
//! The rest of the kernel should use the `ArchImpl` type alias to access
//! architecture-specific functions and types.

use crate::process::{
Task,
owned::OwnedTask,
thread_group::signal::{SigId, ksigaction::UserspaceSigAction},
use crate::{
memory::uaccess::UserCopyable,
process::{
Task,
owned::OwnedTask,
thread_group::signal::{SigId, ksigaction::UserspaceSigAction},
},
};
use alloc::sync::Arc;
use libkernel::{
Expand All @@ -26,6 +29,9 @@ pub trait Arch: CpuOps + VirtualMemory {
/// with this type.
type UserContext: Sized + Send + Sync + Clone;

/// The type for GP regs copied via `PTRACE_GETREGSET`.
type PTraceGpRegs: UserCopyable + for<'a> From<&'a Self::UserContext>;

fn name() -> &'static str;

fn cpu_count() -> usize;
Expand Down
12 changes: 8 additions & 4 deletions src/memory/fault.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{process::ProcVM, sched::current::current_task};
use crate::{process::ProcVM, sync::SpinLock};
use alloc::boxed::Box;
use alloc::sync::Arc;
use libkernel::{
PageInfo, UserAddressSpace,
error::{KernelError, MapError, Result},
Expand Down Expand Up @@ -38,10 +39,12 @@ pub enum FaultResolution {

/// Handle a page fault when a PTE is not present.
pub fn handle_demand_fault(
vm: &mut ProcVM,
proc_vm: Arc<SpinLock<ProcVM>>,
faulting_addr: VA,
access_kind: AccessKind,
) -> Result<FaultResolution> {
let mut vm = proc_vm.lock_save_irq();

let vma = match vm.find_vma_for_fault(faulting_addr, access_kind) {
Some(vma) => vma,
None => return Ok(FaultResolution::Denied),
Expand All @@ -52,6 +55,8 @@ pub fn handle_demand_fault(
let page_va = faulting_addr.page_aligned();

if let Some(vma_read) = vma.resolve_fault(faulting_addr) {
drop(vm);

Ok(FaultResolution::Deferred(Box::new(async move {
let pg_buf = &mut new_page.as_slice_mut()
[vma_read.page_offset..vma_read.page_offset + vma_read.read_len];
Expand All @@ -60,8 +65,7 @@ pub fn handle_demand_fault(

// Since the above may have put the task to sleep, revalidate the
// VMA access.
let task = current_task();
let mut vm = task.vm.lock_save_irq();
let mut vm = proc_vm.lock_save_irq();

// If the handler in the deferred case is no longer valid. Allow
// the program to back to user-space without touching the page
Expand Down
1 change: 1 addition & 0 deletions src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod brk;
pub mod fault;
pub mod mmap;
pub mod page;
pub mod process_vm;
pub mod uaccess;

pub type PageOffsetTranslator = libkernel::memory::pg_offset::PageOffsetTranslator<ArchImpl>;
Expand Down
117 changes: 117 additions & 0 deletions src/memory/process_vm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use core::{cmp::min, slice};

use super::{
PageOffsetTranslator,
uaccess::{copy_obj_array_from_user, copy_to_user_slice},
};
use crate::{
fs::syscalls::iov::IoVec,
process::{
TaskDescriptor, Tid, find_task_by_descriptor,
thread_group::{Tgid, pid::PidT},
},
};
use libkernel::{
error::{KernelError, Result},
memory::{PAGE_SIZE, address::TUA, proc_vm::vmarea::AccessKind},
};

pub async fn sys_process_vm_readv(
pid: PidT,
local_iov: TUA<IoVec>,
liov_count: usize,
remote_iov: TUA<IoVec>,
riov_count: usize,
_flags: usize,
) -> Result<usize> {
let tgid = Tgid::from_pid_t(pid);
let remote_proc =
find_task_by_descriptor(&TaskDescriptor::from_tgid_tid(tgid, Tid::from_tgid(tgid)))
.ok_or(KernelError::NoProcess)?;
let local_iovs = copy_obj_array_from_user(local_iov, liov_count).await?;
let remote_iovs = copy_obj_array_from_user(remote_iov, riov_count).await?;

let mut total_bytes_copied = 0;

let mut local_iov_idx = 0;
let mut local_iov_curr_offset = 0;

let mut remote_iov_idx = 0;
let mut remote_iov_curr_offset = 0;

while let Some(remote_iov) = remote_iovs.get(remote_iov_idx)
&& let Some(local_iov) = local_iovs.get(local_iov_idx)
{
let remote_remaining = remote_iov.iov_len - remote_iov_curr_offset;
let local_remaining = local_iov.iov_len - local_iov_curr_offset;

let remote_va = remote_iov.iov_base.add_bytes(remote_iov_curr_offset);

let chunk_sz = min(
PAGE_SIZE - remote_va.page_offset(),
min(remote_remaining, local_remaining),
);

// If we have nothing left to copy in current vectors, advance them.
if chunk_sz == 0 {
if remote_remaining == 0 {
remote_iov_idx += 1;
remote_iov_curr_offset = 0;
}

if local_remaining == 0 {
local_iov_idx += 1;
local_iov_curr_offset = 0;
}

continue;
}

let copy_result = async {
// Get the page (pins it)
// SAFETY: We only read.
let remote_page = unsafe { remote_proc.get_page(remote_va, AccessKind::Read).await? };

// Map physical page to kernel virtual address (Direct Map)
let remote_pg_slice = unsafe {
slice::from_raw_parts(
remote_page
.region()
.start_address()
.to_va::<PageOffsetTranslator>()
.cast::<u8>()
.add_bytes(remote_va.page_offset())
.as_ptr(),
chunk_sz,
)
};

// Copy to local user memory
copy_to_user_slice(
remote_pg_slice,
local_iov.iov_base.add_bytes(local_iov_curr_offset),
)
.await
}
.await;

match copy_result {
Ok(_) => {
total_bytes_copied += chunk_sz;
remote_iov_curr_offset += chunk_sz;
local_iov_curr_offset += chunk_sz;
}
Err(e) => {
if total_bytes_copied > 0 {
// Partial success: return what we got so far.
return Ok(total_bytes_copied);
} else {
// No data copied at all: return the error.
return Err(e);
}
}
}
}

Ok(total_bytes_copied)
}
Loading