refactor: fix warnings
This commit is contained in:
parent
4c3374de36
commit
4ffbb8c115
@ -1,9 +1,6 @@
|
||||
use crate::{BlockAllocator, Bvec, FileInode};
|
||||
use alloc::boxed::Box;
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
stat::{DirectoryEntry, OpenFlags, Stat},
|
||||
};
|
||||
use libsys::{error::Errno, stat::Stat};
|
||||
use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
|
||||
pub struct DirInode<A: BlockAllocator + Copy + 'static> {
|
||||
@ -40,7 +37,7 @@ impl<A: BlockAllocator + Copy + 'static> VnodeImpl for DirInode<A> {
|
||||
Ok(Stat {
|
||||
size: 0,
|
||||
blksize: 4096,
|
||||
mode: props.mode
|
||||
mode: props.mode,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ pub trait CharDevice {
|
||||
/// Performs a TTY control request
|
||||
fn ioctl(&self, cmd: IoctlCmd, ptr: usize, lim: usize) -> Result<usize, Errno>;
|
||||
|
||||
/// Returns `true` if the device is ready for an operation
|
||||
fn is_ready(&self, write: bool) -> Result<bool, Errno>;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,9 @@ impl File {
|
||||
/// File has to be closed on execve() calls
|
||||
pub const CLOEXEC: u32 = 1 << 2;
|
||||
|
||||
/// Special position for cache-readdir: "." entry
|
||||
pub const POS_CACHE_DOT: usize = usize::MAX - 1;
|
||||
/// Special position for cache-readdir: ".." entry
|
||||
pub const POS_CACHE_DOT_DOT: usize = usize::MAX;
|
||||
|
||||
/// Constructs a new file handle for a regular file
|
||||
@ -123,6 +125,7 @@ impl File {
|
||||
self.flags & Self::CLOEXEC != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if the file is ready for an operation
|
||||
pub fn is_ready(&self, write: bool) -> Result<bool, Errno> {
|
||||
match &self.inner {
|
||||
FileInner::Normal(inner) => inner.vnode.is_ready(write),
|
||||
@ -169,6 +172,7 @@ impl File {
|
||||
Ok(offset + count)
|
||||
}
|
||||
|
||||
/// Reads directory entries into the target buffer
|
||||
pub fn readdir(&mut self, entries: &mut [DirectoryEntry]) -> Result<usize, Errno> {
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
|
@ -10,7 +10,9 @@ use libsys::{
|
||||
pub struct Ioctx {
|
||||
root: VnodeRef,
|
||||
cwd: VnodeRef,
|
||||
/// Process user ID
|
||||
pub uid: UserId,
|
||||
/// Process group ID
|
||||
pub gid: GroupId,
|
||||
}
|
||||
|
||||
@ -123,6 +125,7 @@ impl Ioctx {
|
||||
node.open(opts)
|
||||
}
|
||||
|
||||
/// Changes current working directory of the process
|
||||
pub fn chdir(&mut self, path: &str) -> Result<(), Errno> {
|
||||
let node = self.find(None, path, true)?;
|
||||
if !node.is_directory() {
|
||||
|
@ -31,6 +31,7 @@ pub(crate) struct TreeNode {
|
||||
|
||||
/// File property cache struct
|
||||
pub struct VnodeProps {
|
||||
/// Node permissions and type
|
||||
pub mode: FileMode,
|
||||
}
|
||||
|
||||
@ -74,6 +75,7 @@ pub trait VnodeImpl {
|
||||
/// Resizes the file storage if necessary.
|
||||
fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno>;
|
||||
|
||||
/// Read directory entries into target buffer
|
||||
fn readdir(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
@ -87,6 +89,7 @@ pub trait VnodeImpl {
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno>;
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno>;
|
||||
|
||||
/// Performs filetype-specific request
|
||||
@ -104,7 +107,9 @@ impl Vnode {
|
||||
/// be seeked to arbitrary offsets
|
||||
pub const SEEKABLE: u32 = 1 << 0;
|
||||
|
||||
/// If set, readdir() uses only in-memory node tree
|
||||
pub const CACHE_READDIR: u32 = 1 << 1;
|
||||
/// If set, stat() uses only in-memory stat data
|
||||
pub const CACHE_STAT: u32 = 1 << 2;
|
||||
|
||||
/// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node
|
||||
@ -178,6 +183,7 @@ impl Vnode {
|
||||
self.kind
|
||||
}
|
||||
|
||||
/// Returns flags of the vnode
|
||||
#[inline(always)]
|
||||
pub const fn flags(&self) -> u32 {
|
||||
self.flags
|
||||
@ -476,6 +482,7 @@ impl Vnode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the node is ready for operation
|
||||
pub fn is_ready(self: &VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
if let Some(ref mut data) = *self.data() {
|
||||
data.is_ready(self.clone(), write)
|
||||
@ -484,6 +491,7 @@ impl Vnode {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if given [Ioctx] has `access` permissions to the vnode
|
||||
pub fn check_access(&self, _ioctx: &Ioctx, access: AccessMode) -> Result<(), Errno> {
|
||||
let props = self.props.borrow();
|
||||
let mode = props.mode;
|
||||
|
@ -28,7 +28,6 @@ pub struct Gic {
|
||||
gicd: InitOnce<Gicd>,
|
||||
gicd_base: usize,
|
||||
gicc_base: usize,
|
||||
scheduler_irq: IrqNumber,
|
||||
table: IrqSafeSpinLock<[Option<&'static (dyn IntSource + Sync)>; MAX_IRQ]>,
|
||||
}
|
||||
|
||||
@ -124,13 +123,12 @@ impl Gic {
|
||||
/// # Safety
|
||||
///
|
||||
/// Does not perform `gicd_base` and `gicc_base` validation.
|
||||
pub const unsafe fn new(gicd_base: usize, gicc_base: usize, scheduler_irq: IrqNumber) -> Self {
|
||||
pub const unsafe fn new(gicd_base: usize, gicc_base: usize) -> Self {
|
||||
Self {
|
||||
gicc: InitOnce::new(),
|
||||
gicd: InitOnce::new(),
|
||||
gicd_base,
|
||||
gicc_base,
|
||||
scheduler_irq,
|
||||
table: IrqSafeSpinLock::new([None; MAX_IRQ]),
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,6 @@ pub fn intc() -> &'static impl IntController<IrqNumber = IrqNumber> {
|
||||
|
||||
static UART0: Pl011 = unsafe { Pl011::new(UART0_BASE, UART0_IRQ) };
|
||||
static RTC: Pl031 = unsafe { Pl031::new(RTC_BASE, RTC_IRQ) };
|
||||
static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE, LOCAL_TIMER_IRQ) };
|
||||
static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) };
|
||||
static PCIE: GenericPcieHost = unsafe { GenericPcieHost::new(ECAM_BASE, 8) };
|
||||
static LOCAL_TIMER: GenericTimer = GenericTimer::new(LOCAL_TIMER_IRQ);
|
||||
|
@ -114,7 +114,7 @@ macro_rules! errorln {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _debug(level: Level, args: fmt::Arguments) {
|
||||
pub fn _debug(_level: Level, args: fmt::Arguments) {
|
||||
use crate::arch::machine;
|
||||
use fmt::Write;
|
||||
|
||||
|
@ -34,6 +34,7 @@ pub trait TtyDevice<const N: usize>: SerialDevice {
|
||||
/// Returns a reference to character device's ring buffer
|
||||
fn ring(&self) -> &CharRing<N>;
|
||||
|
||||
/// Returns `true` if the TTY is ready for an operation
|
||||
fn is_ready(&self, write: bool) -> Result<bool, Errno> {
|
||||
let ring = self.ring();
|
||||
if write {
|
||||
@ -265,6 +266,7 @@ impl<const N: usize> CharRing<N> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a character/line is available for reception
|
||||
pub fn is_readable(&self) -> bool {
|
||||
let inner = self.inner.lock();
|
||||
let config = self.config.lock();
|
||||
|
@ -28,6 +28,7 @@ unsafe impl BlockAllocator for MemfsBlockAlloc {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a filesystem instance based on `options`
|
||||
pub fn create_filesystem(options: &MountOptions) -> Result<VnodeRef, Errno> {
|
||||
let fs_name = options.fs.unwrap();
|
||||
|
||||
|
@ -210,6 +210,9 @@ impl Space {
|
||||
}
|
||||
}
|
||||
|
||||
/// Translates a virtual address into a corresponding physical one.
|
||||
///
|
||||
/// Only works for 4K pages atm.
|
||||
// TODO extract attributes
|
||||
pub fn translate(&mut self, virt: usize) -> Result<usize, Errno> {
|
||||
let l0i = virt >> 30;
|
||||
@ -264,6 +267,8 @@ impl Space {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Allocates a contiguous region from the address space and maps
|
||||
/// physical pages to it
|
||||
pub fn allocate(
|
||||
&mut self,
|
||||
start: usize,
|
||||
@ -288,6 +293,8 @@ impl Space {
|
||||
Err(Errno::OutOfMemory)
|
||||
}
|
||||
|
||||
/// Removes a single 4K page mapping from the table and
|
||||
/// releases the underlying physical memory
|
||||
pub fn unmap_single(&mut self, page: usize) -> Result<(), Errno> {
|
||||
let l0i = page >> 30;
|
||||
let l1i = (page >> 21) & 0x1FF;
|
||||
@ -304,7 +311,7 @@ impl Space {
|
||||
|
||||
let phys = unsafe { entry.address_unchecked() };
|
||||
unsafe {
|
||||
phys::free_page(phys);
|
||||
phys::free_page(phys)?;
|
||||
}
|
||||
l2_table[l2i] = Entry::invalid();
|
||||
|
||||
@ -317,6 +324,7 @@ impl Space {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Releases a range of virtual pages and their corresponding physical pages
|
||||
pub fn free(&mut self, start: usize, len: usize) -> Result<(), Errno> {
|
||||
for i in 0..len {
|
||||
self.unmap_single(start + i * 0x1000)?;
|
||||
|
@ -22,25 +22,30 @@ impl ProcessIo {
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
/// Sets controlling terminal for the process
|
||||
pub fn set_ctty(&mut self, node: VnodeRef) {
|
||||
assert_eq!(node.kind(), VnodeKind::Char);
|
||||
self.ctty = Some(node);
|
||||
}
|
||||
|
||||
/// Returns current controlling terminal of the process
|
||||
pub fn ctty(&mut self) -> Option<VnodeRef> {
|
||||
self.ctty.clone()
|
||||
}
|
||||
|
||||
/// Returns user ID of the process
|
||||
#[inline(always)]
|
||||
pub fn uid(&self) -> UserId {
|
||||
self.ioctx.as_ref().unwrap().uid
|
||||
}
|
||||
|
||||
/// Returns group ID of the process
|
||||
#[inline(always)]
|
||||
pub fn gid(&self) -> GroupId {
|
||||
self.ioctx.as_ref().unwrap().gid
|
||||
}
|
||||
|
||||
/// Changes (if permitted) user ID of the process
|
||||
#[inline(always)]
|
||||
pub fn set_uid(&mut self, uid: UserId) -> Result<(), Errno> {
|
||||
let old_uid = self.uid();
|
||||
@ -54,6 +59,7 @@ impl ProcessIo {
|
||||
}
|
||||
}
|
||||
|
||||
/// Changes (if permitted) group ID of the process
|
||||
#[inline(always)]
|
||||
pub fn set_gid(&mut self, gid: GroupId) -> Result<(), Errno> {
|
||||
let old_gid = self.gid();
|
||||
@ -67,6 +73,7 @@ impl ProcessIo {
|
||||
}
|
||||
}
|
||||
|
||||
/// Clones a file descriptor into an available slot or, if specified, requested one
|
||||
pub fn duplicate_file(&mut self, src: FileDescriptor, dst: Option<FileDescriptor>) -> Result<FileDescriptor, Errno> {
|
||||
let file_ref = self.file(src)?;
|
||||
if let Some(dst) = dst {
|
||||
|
@ -20,25 +20,6 @@ pub mod sched;
|
||||
pub use sched::Scheduler;
|
||||
pub(self) use sched::SCHED;
|
||||
|
||||
// macro_rules! spawn {
|
||||
// (fn ($dst_arg:ident : usize) $body:block, $src_arg:expr) => {{
|
||||
// #[inline(never)]
|
||||
// extern "C" fn __inner_func($dst_arg : usize) -> ! {
|
||||
// let __res = $body;
|
||||
// {
|
||||
// #![allow(unreachable_code)]
|
||||
// SCHED.current_process().exit(__res);
|
||||
// panic!();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let __proc = $crate::proc::Process::new_kernel(__inner_func, $src_arg).unwrap();
|
||||
// $crate::proc::SCHED.enqueue(__proc.id());
|
||||
// }};
|
||||
//
|
||||
// (fn () $body:block) => (spawn!(fn (_arg: usize) $body, 0usize))
|
||||
// }
|
||||
|
||||
/// Performs a task switch.
|
||||
///
|
||||
/// See [Scheduler::switch]
|
||||
@ -46,12 +27,6 @@ pub fn switch() {
|
||||
SCHED.switch(false);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn process(id: Pid) -> ProcessRef {
|
||||
PROCESSES.lock().get(&id).unwrap().clone()
|
||||
}
|
||||
|
||||
/// Global list of all processes in the system
|
||||
pub(self) static PROCESSES: IrqSafeSpinLock<BTreeMap<Pid, ProcessRef>> =
|
||||
IrqSafeSpinLock::new(BTreeMap::new());
|
||||
|
||||
|
@ -8,18 +8,16 @@ use crate::mem::{
|
||||
use crate::proc::{
|
||||
wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, PROCESSES, SCHED,
|
||||
};
|
||||
use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard};
|
||||
use crate::sync::IrqSafeSpinLock;
|
||||
use alloc::{rc::Rc, vec::Vec};
|
||||
use core::alloc::Layout;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
mem::memcpy,
|
||||
proc::{ExitCode, Pid},
|
||||
signal::Signal,
|
||||
mem::memcpy,
|
||||
ProgramArgs,
|
||||
};
|
||||
use vfs::{VnodeKind, VnodeRef};
|
||||
|
||||
/// Wrapper type for a process struct reference
|
||||
pub type ProcessRef = Rc<Process>;
|
||||
@ -58,39 +56,47 @@ impl Process {
|
||||
const USTACK_VIRT_TOP: usize = 0x100000000;
|
||||
const USTACK_PAGES: usize = 4;
|
||||
|
||||
/// Returns the process ID
|
||||
#[inline]
|
||||
pub fn id(&self) -> Pid {
|
||||
self.inner.lock().id
|
||||
}
|
||||
|
||||
/// Returns the process session ID
|
||||
#[inline]
|
||||
pub fn sid(&self) -> Pid {
|
||||
self.inner.lock().sid
|
||||
}
|
||||
|
||||
/// Returns parent's [Pid]
|
||||
#[inline]
|
||||
pub fn pgid(&self) -> Pid {
|
||||
self.inner.lock().pgid
|
||||
}
|
||||
|
||||
/// Returns parent's [Pid]
|
||||
#[inline]
|
||||
pub fn ppid(&self) -> Option<Pid> {
|
||||
self.inner.lock().ppid
|
||||
}
|
||||
|
||||
/// Sets a new group id for the process
|
||||
pub fn set_pgid(&self, pgid: Pid) {
|
||||
self.inner.lock().pgid = pgid;
|
||||
}
|
||||
|
||||
/// Sets a new session id for the process
|
||||
pub fn set_sid(&self, sid: Pid) {
|
||||
self.inner.lock().sid = sid;
|
||||
}
|
||||
|
||||
/// Returns [Rc]-reference to current process
|
||||
#[inline]
|
||||
pub fn current() -> ProcessRef {
|
||||
Thread::current().owner().unwrap()
|
||||
}
|
||||
|
||||
/// Executes a closure performing manipulations on the process address space
|
||||
#[inline]
|
||||
pub fn manipulate_space<R, F>(&self, f: F) -> R
|
||||
where
|
||||
@ -99,6 +105,7 @@ impl Process {
|
||||
f(self.inner.lock().space.as_mut().unwrap())
|
||||
}
|
||||
|
||||
/// Creates a new kernel process
|
||||
pub fn new_kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<ProcessRef, Errno> {
|
||||
let id = new_kernel_pid();
|
||||
let thread = Thread::new_kernel(Some(id), entry, arg)?;
|
||||
@ -126,6 +133,7 @@ impl Process {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Adds all of the process threads to scheduler queue
|
||||
pub fn enqueue(&self) {
|
||||
let inner = self.inner.lock();
|
||||
for &tid in inner.threads.iter() {
|
||||
@ -168,12 +176,14 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
/// Immediately delivers a signal to requested thread
|
||||
pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
thread.enter_signal(signal, ttbr0);
|
||||
}
|
||||
|
||||
/// Crates a new thread in the process
|
||||
pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result<u32, Errno> {
|
||||
let mut lock = self.inner.lock();
|
||||
|
||||
@ -264,6 +274,8 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
/// Terminates a thread of the process. If the thread is the only
|
||||
/// one remaining, process itself is exited (see [Process::exit])
|
||||
pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
|
||||
let switch = {
|
||||
let switch = thread.state() == ThreadState::Running;
|
||||
@ -337,11 +349,11 @@ impl Process {
|
||||
phys
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate)?;
|
||||
let flags = MapAttributes::SH_OUTER |
|
||||
MapAttributes::NOT_GLOBAL |
|
||||
MapAttributes::UXN |
|
||||
MapAttributes::PXN |
|
||||
MapAttributes::AP_BOTH_READONLY;
|
||||
let flags = MapAttributes::SH_OUTER
|
||||
| MapAttributes::NOT_GLOBAL
|
||||
| MapAttributes::UXN
|
||||
| MapAttributes::PXN
|
||||
| MapAttributes::AP_BOTH_READONLY;
|
||||
space.map(page_virt, page, flags)?;
|
||||
page
|
||||
};
|
||||
@ -361,17 +373,21 @@ impl Process {
|
||||
phys
|
||||
} else {
|
||||
let page = phys::alloc_page(PageUsage::UserPrivate)?;
|
||||
let flags = MapAttributes::SH_OUTER |
|
||||
MapAttributes::NOT_GLOBAL |
|
||||
MapAttributes::UXN |
|
||||
MapAttributes::PXN |
|
||||
MapAttributes::AP_BOTH_READONLY;
|
||||
let flags = MapAttributes::SH_OUTER
|
||||
| MapAttributes::NOT_GLOBAL
|
||||
| MapAttributes::UXN
|
||||
| MapAttributes::PXN
|
||||
| MapAttributes::AP_BOTH_READONLY;
|
||||
space.map(page_virt, page, flags)?;
|
||||
page
|
||||
};
|
||||
|
||||
unsafe {
|
||||
memcpy((mem::virtualize(page_phys) + (dst % 4096)) as *mut u8, src.as_ptr(), src.len());
|
||||
memcpy(
|
||||
(mem::virtualize(page_phys) + (dst % 4096)) as *mut u8,
|
||||
src.as_ptr(),
|
||||
src.len(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -405,7 +421,7 @@ impl Process {
|
||||
argc: argv.len(),
|
||||
argv: base + argv_offset,
|
||||
storage: base,
|
||||
size: offset + core::mem::size_of::<ProgramArgs>()
|
||||
size: offset + core::mem::size_of::<ProgramArgs>(),
|
||||
};
|
||||
Self::write_paged(space, base + offset, data)?;
|
||||
|
||||
|
@ -48,14 +48,6 @@ impl Scheduler {
|
||||
self.inner.get().lock().queue.retain(|&p| p != tid)
|
||||
}
|
||||
|
||||
pub fn debug(&self) {
|
||||
let lock = self.inner.get().lock();
|
||||
debugln!("Scheduler queue:");
|
||||
for &tid in lock.queue.iter() {
|
||||
debugln!("TID: {:?}", tid);
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs initial process entry.
|
||||
///
|
||||
/// # Safety
|
||||
@ -132,6 +124,7 @@ impl Scheduler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [Rc]-reference to currently running Thread
|
||||
pub fn current_thread(&self) -> ThreadRef {
|
||||
let inner = self.inner.get().lock();
|
||||
let id = inner.current.unwrap();
|
||||
|
@ -1,5 +1,10 @@
|
||||
//! Facilities for controlling threads - smallest units of
|
||||
//! execution in the operating system
|
||||
use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
use crate::proc::{wait::{Wait, WaitStatus}, Process, ProcessRef, SCHED, THREADS};
|
||||
use crate::proc::{
|
||||
wait::{Wait, WaitStatus},
|
||||
Process, ProcessRef, SCHED, THREADS,
|
||||
};
|
||||
use crate::sync::IrqSafeSpinLock;
|
||||
use crate::util::InitOnce;
|
||||
use alloc::rc::Rc;
|
||||
@ -13,6 +18,7 @@ use libsys::{
|
||||
|
||||
pub use crate::arch::platform::context::{self, Context};
|
||||
|
||||
/// Convenience wrapper for [Thread] references
|
||||
pub type ThreadRef = Rc<Thread>;
|
||||
|
||||
/// List of possible process states
|
||||
@ -38,6 +44,7 @@ struct ThreadInner {
|
||||
signal_stack: usize,
|
||||
}
|
||||
|
||||
/// Thread control data
|
||||
pub struct Thread {
|
||||
inner: IrqSafeSpinLock<ThreadInner>,
|
||||
exit_wait: Wait,
|
||||
@ -48,21 +55,25 @@ pub struct Thread {
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
/// Returns currently active thread [Rc]-reference
|
||||
#[inline]
|
||||
pub fn current() -> ThreadRef {
|
||||
SCHED.current_thread()
|
||||
}
|
||||
|
||||
/// Returns a reference to thread `tid`, if it exists
|
||||
#[inline]
|
||||
pub fn get(tid: u32) -> Option<ThreadRef> {
|
||||
THREADS.lock().get(&tid).cloned()
|
||||
}
|
||||
|
||||
/// Returns the owner process
|
||||
#[inline]
|
||||
pub fn owner(&self) -> Option<ProcessRef> {
|
||||
self.inner.lock().owner.and_then(Process::get)
|
||||
}
|
||||
|
||||
/// Returns [Pid] of the owner process
|
||||
pub fn owner_id(&self) -> Option<Pid> {
|
||||
self.inner.lock().owner
|
||||
}
|
||||
@ -127,6 +138,7 @@ impl Thread {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Creates a fork thread cloning `frame` context
|
||||
pub fn fork(
|
||||
owner: Option<Pid>,
|
||||
frame: &ExceptionFrame,
|
||||
@ -155,6 +167,7 @@ impl Thread {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Returns the thread ID
|
||||
#[inline]
|
||||
pub fn id(&self) -> u32 {
|
||||
self.inner.lock().id
|
||||
@ -230,6 +243,7 @@ impl Thread {
|
||||
lock.wait_status = WaitStatus::Pending;
|
||||
}
|
||||
|
||||
/// Suspends current thread until thread `tid` terminates
|
||||
pub fn waittid(tid: u32) -> Result<(), Errno> {
|
||||
loop {
|
||||
let thread = THREADS
|
||||
@ -247,17 +261,20 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates pending wait status
|
||||
pub fn set_wait_status(&self, status: WaitStatus) {
|
||||
let mut lock = self.inner.lock();
|
||||
lock.wait_status = status;
|
||||
}
|
||||
|
||||
/// Resets wait channel back to initial state
|
||||
pub fn reset_wait(&self) {
|
||||
let mut lock = self.inner.lock();
|
||||
lock.pending_wait = None;
|
||||
lock.wait_status = WaitStatus::Done;
|
||||
}
|
||||
|
||||
/// Returns status of the thread's pending wait
|
||||
pub fn wait_status(&self) -> WaitStatus {
|
||||
self.inner.lock().wait_status
|
||||
}
|
||||
@ -279,11 +296,13 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the thread state
|
||||
#[inline]
|
||||
pub fn state(&self) -> State {
|
||||
self.inner.lock().state
|
||||
}
|
||||
|
||||
/// Sets the thread's owner process ID
|
||||
pub fn set_owner(&self, pid: Pid) {
|
||||
self.inner.lock().owner = Some(pid);
|
||||
}
|
||||
@ -295,6 +314,7 @@ impl Thread {
|
||||
lock.signal_stack = stack;
|
||||
}
|
||||
|
||||
/// Sets up a context for signal handler
|
||||
pub fn setup_signal(self: ThreadRef, signal: Signal, ttbr0: usize) {
|
||||
if self
|
||||
.signal_pending
|
||||
@ -312,7 +332,6 @@ impl Thread {
|
||||
}
|
||||
|
||||
let signal_ctx = unsafe { &mut *self.signal_ctx.get() };
|
||||
let src_ctx = self.ctx.get();
|
||||
|
||||
debugln!(
|
||||
"Signal entry: tid={}, pc={:#x}, sp={:#x}, ttbr0={:#x}",
|
||||
@ -330,7 +349,6 @@ impl Thread {
|
||||
lock.signal_stack,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Switches process main thread to a signal handler
|
||||
@ -346,6 +364,7 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupts pending wait (from signal routines)
|
||||
pub fn interrupt_wait(&self, enqueue: bool) {
|
||||
let mut lock = self.inner.lock();
|
||||
let tid = lock.id;
|
||||
@ -356,6 +375,8 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
/// Cleans up any resources of the thread and aborts
|
||||
/// pending wait, if any
|
||||
pub fn terminate(&self, status: ExitCode) {
|
||||
let mut lock = self.inner.lock();
|
||||
lock.state = State::Finished;
|
||||
@ -376,6 +397,7 @@ impl Drop for Thread {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocates a new thread ID
|
||||
pub fn new_tid() -> u32 {
|
||||
static LAST: AtomicU32 = AtomicU32::new(1);
|
||||
let id = LAST.fetch_add(1, Ordering::Relaxed);
|
||||
|
@ -12,13 +12,18 @@ use libsys::{error::Errno, stat::FdSet};
|
||||
/// waiting for some event to happen.
|
||||
pub struct Wait {
|
||||
queue: IrqSafeSpinLock<LinkedList<u32>>,
|
||||
#[allow(dead_code)]
|
||||
name: &'static str
|
||||
}
|
||||
|
||||
/// Status of a (possibly) pending wait
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum WaitStatus {
|
||||
/// In progress
|
||||
Pending,
|
||||
/// Wait was interrupted by a signal
|
||||
Interrupted,
|
||||
/// Channel reported data available
|
||||
Done,
|
||||
}
|
||||
|
||||
@ -28,6 +33,8 @@ struct Timeout {
|
||||
}
|
||||
|
||||
static TICK_LIST: IrqSafeSpinLock<LinkedList<Timeout>> = IrqSafeSpinLock::new(LinkedList::new());
|
||||
/// Global wait channel for blocking on select. Gets notified
|
||||
/// of ANY I/O operations available, so not very efficient.
|
||||
pub static WAIT_SELECT: Wait = Wait::new("select");
|
||||
|
||||
/// Checks for any timed out wait channels and interrupts them
|
||||
@ -63,6 +70,8 @@ pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Suspends current process until some file descriptor
|
||||
/// signals data available
|
||||
pub fn select(
|
||||
thread: ThreadRef,
|
||||
mut rfds: Option<&mut FdSet>,
|
||||
@ -119,6 +128,7 @@ impl Wait {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt wait pending on the channel
|
||||
pub fn abort(&self, tid: u32, enqueue: bool) {
|
||||
let mut queue = self.queue.lock();
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
|
@ -36,6 +36,7 @@ fn is_el0_accessible(virt: usize, write: bool) -> bool {
|
||||
res & 1 == 0
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a `T` reference
|
||||
pub fn struct_ref<'a, T>(base: usize) -> Result<&'a T, Errno> {
|
||||
let layout = Layout::new::<T>();
|
||||
if base % layout.align() != 0 {
|
||||
@ -49,6 +50,7 @@ pub fn struct_ref<'a, T>(base: usize) -> Result<&'a T, Errno> {
|
||||
Ok(unsafe { &*(bytes.as_ptr() as *const T) })
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a `T` mutable reference
|
||||
pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> {
|
||||
let layout = Layout::new::<T>();
|
||||
if base % layout.align() != 0 {
|
||||
@ -62,6 +64,7 @@ pub fn struct_mut<'a, T>(base: usize) -> Result<&'a mut T, Errno> {
|
||||
Ok(unsafe { &mut *(bytes.as_mut_ptr() as *mut T) })
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a `T` array buffer of size `count`
|
||||
pub fn struct_buf_ref<'a, T>(base: usize, count: usize) -> Result<&'a [T], Errno> {
|
||||
let layout = Layout::array::<T>(count).unwrap();
|
||||
if base % layout.align() != 0 {
|
||||
@ -75,6 +78,7 @@ pub fn struct_buf_ref<'a, T>(base: usize, count: usize) -> Result<&'a [T], Errno
|
||||
Ok(unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *const T, count) })
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a `T` array buffer of size `count`
|
||||
pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], Errno> {
|
||||
let layout = Layout::array::<T>(count).unwrap();
|
||||
if base % layout.align() != 0 {
|
||||
@ -88,6 +92,7 @@ pub fn struct_buf_mut<'a, T>(base: usize, count: usize) -> Result<&'a mut [T], E
|
||||
Ok(unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, count) })
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a `Option<&'a T>`
|
||||
pub fn option_struct_ref<'a, T>(base: usize) -> Result<Option<&'a T>, Errno> {
|
||||
if base == 0 {
|
||||
Ok(None)
|
||||
@ -96,6 +101,7 @@ pub fn option_struct_ref<'a, T>(base: usize) -> Result<Option<&'a T>, Errno> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a `Option<&'a mut T>`
|
||||
pub fn option_struct_mut<'a, T>(base: usize) -> Result<Option<&'a mut T>, Errno> {
|
||||
if base == 0 {
|
||||
Ok(None)
|
||||
@ -104,6 +110,8 @@ pub fn option_struct_mut<'a, T>(base: usize) -> Result<Option<&'a mut T>, Errno>
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates that the argument pointer is accessible for requested operation
|
||||
/// for current process
|
||||
pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
|
||||
if base > mem::KERNEL_OFFSET || base + len > mem::KERNEL_OFFSET {
|
||||
invalid_memory!(
|
||||
@ -144,16 +152,19 @@ pub fn validate_ptr(base: usize, len: usize, write: bool) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a byte buffer
|
||||
pub fn buf_ref<'a>(base: usize, len: usize) -> Result<&'a [u8], Errno> {
|
||||
validate_ptr(base, len, false)?;
|
||||
Ok(unsafe { core::slice::from_raw_parts(base as *const u8, len) })
|
||||
}
|
||||
|
||||
/// Checks given argument and interprets it as a mutable byte buffer
|
||||
pub fn buf_mut<'a>(base: usize, len: usize) -> Result<&'a mut [u8], Errno> {
|
||||
validate_ptr(base, len, true)?;
|
||||
Ok(unsafe { core::slice::from_raw_parts_mut(base as *mut u8, len) })
|
||||
}
|
||||
|
||||
/// Checks possibly NULL given argument and interprets it as a byte buffer
|
||||
pub fn option_buf_ref<'a>(base: usize, len: usize) -> Result<Option<&'a [u8]>, Errno> {
|
||||
if base == 0 {
|
||||
Ok(None)
|
||||
@ -162,6 +173,7 @@ pub fn option_buf_ref<'a>(base: usize, len: usize) -> Result<Option<&'a [u8]>, E
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks possibly NULL given argument and interprets it as a mutable byte buffer
|
||||
pub fn option_buf_mut<'a>(base: usize, len: usize) -> Result<Option<&'a mut [u8]>, Errno> {
|
||||
if base == 0 {
|
||||
Ok(None)
|
||||
|
@ -14,7 +14,7 @@ use libsys::{
|
||||
debug::TraceLevel,
|
||||
error::Errno,
|
||||
ioctl::IoctlCmd,
|
||||
proc::{ExitCode, Pid, MemoryAccess, MemoryMap},
|
||||
proc::{ExitCode, Pid, MemoryAccess},
|
||||
signal::{Signal, SignalDestination},
|
||||
stat::{
|
||||
AccessMode, DirectoryEntry, FdSet, FileDescriptor, FileMode, GroupId, MountOptions,
|
||||
@ -208,7 +208,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
let acc = MemoryAccess::from_bits(args[2] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
let flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
let _flags = MemoryAccess::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
|
||||
let mut attrs = MapAttributes::NOT_GLOBAL | MapAttributes::SH_OUTER | MapAttributes::PXN;
|
||||
if !acc.contains(MemoryAccess::READ) {
|
||||
@ -386,7 +386,7 @@ pub fn syscall(num: SystemCall, args: &[usize]) -> Result<usize, Errno> {
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
|
||||
if let Some(ctty) = io.ctty() {
|
||||
if let Some(_ctty) = io.ctty() {
|
||||
todo!();
|
||||
}
|
||||
|
||||
|
@ -472,5 +472,5 @@ pub fn sys_mmap(
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn sys_munmap(addr: usize, len: usize) -> Result<(), Errno> {
|
||||
Errno::from_syscall_unit(unsafe { syscall!(SystemCall::UnmapMemory, argn!(addr), argn!(len)) })
|
||||
Errno::from_syscall_unit(syscall!(SystemCall::UnmapMemory, argn!(addr), argn!(len)))
|
||||
}
|
||||
|
@ -274,8 +274,7 @@ impl fmt::Display for FileMode {
|
||||
choose(self.contains(Self::OTHER_READ), 'r', '-'),
|
||||
choose(self.contains(Self::OTHER_WRITE), 'w', '-'),
|
||||
choose(self.contains(Self::OTHER_EXEC), 'x', '-'),
|
||||
);
|
||||
Ok(())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,9 @@
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::mem::{size_of, MaybeUninit};
|
||||
use core::ptr::null_mut;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use libsys::{
|
||||
calls::{sys_mmap, sys_munmap},
|
||||
debug::TraceLevel,
|
||||
error::Errno,
|
||||
mem::memset,
|
||||
proc::{MemoryAccess, MemoryMap},
|
||||
};
|
||||
use memoffset::offset_of;
|
||||
@ -117,7 +114,7 @@ impl Zone {
|
||||
unsafe fn zone_alloc(zone: &mut Zone, size: usize) -> *mut u8 {
|
||||
assert_eq!(size & 15, 0);
|
||||
|
||||
let mut begin = ((zone as *mut _ as usize) + size_of::<Zone>()) as *mut Block;
|
||||
let begin = ((zone as *mut _ as usize) + size_of::<Zone>()) as *mut Block;
|
||||
|
||||
let mut block = begin;
|
||||
while !block.is_null() {
|
||||
@ -168,6 +165,7 @@ unsafe fn alloc_from(list: &mut ZoneList, zone_size: usize, size: usize) -> *mut
|
||||
if !ptr.is_null() {
|
||||
return ptr;
|
||||
}
|
||||
zone = (&mut *zone).next;
|
||||
}
|
||||
|
||||
let zone = match Zone::alloc(zone_size) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::io::{AsRawFd, Error, Read, Write};
|
||||
use crate::io::{AsRawFd, Error, Read};
|
||||
use libsys::{
|
||||
calls::{sys_openat, sys_read, sys_close},
|
||||
stat::{FileDescriptor, FileMode, OpenFlags},
|
||||
|
@ -28,7 +28,7 @@ pub trait AsRawFd {
|
||||
fn as_raw_fd(&self) -> FileDescriptor;
|
||||
}
|
||||
|
||||
pub fn tcgetpgrp(fd: FileDescriptor) -> Result<Pid, Errno> {
|
||||
pub fn tcgetpgrp(_fd: FileDescriptor) -> Result<Pid, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use libusr::io::{self, Read, Write};
|
||||
use libusr::file::File;
|
||||
@ -19,7 +17,7 @@ fn do_cat<F: Read>(mut fd: F) -> Result<(), io::Error> {
|
||||
break;
|
||||
}
|
||||
|
||||
out.write(&buf[..count]);
|
||||
out.write(&buf[..count])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -3,10 +3,8 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use libusr::io::{self, Read, Write};
|
||||
use libusr::io::{self, Read};
|
||||
use libusr::file::File;
|
||||
|
||||
fn line_print(off: usize, line: &[u8]) {
|
||||
|
@ -6,7 +6,7 @@ extern crate libusr;
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{borrow::ToOwned, string::String};
|
||||
use alloc::borrow::ToOwned;
|
||||
use libusr::sys::{
|
||||
stat::{DirectoryEntry, FileMode, OpenFlags, Stat},
|
||||
sys_close, sys_fstatat, sys_openat, sys_readdir, Errno,
|
||||
|
@ -107,7 +107,6 @@ fn main() -> i32 {
|
||||
println!("Interrupt!");
|
||||
continue;
|
||||
}
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
0
|
||||
|
@ -18,11 +18,9 @@ fn main() -> i32 {
|
||||
)
|
||||
.expect("Failed to mount devfs");
|
||||
|
||||
let pid = unsafe { libusr::sys::sys_fork().unwrap() };
|
||||
|
||||
if let Some(pid) = pid {
|
||||
if let Some(pid) = unsafe { sys_fork().unwrap() } {
|
||||
let mut status = 0;
|
||||
libusr::sys::sys_waitpid(pid, &mut status).unwrap();
|
||||
sys_waitpid(pid, &mut status).unwrap();
|
||||
println!("Process {:?} exited with status {}", pid, status);
|
||||
|
||||
loop {
|
||||
@ -31,7 +29,7 @@ fn main() -> i32 {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
libusr::sys::sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
|
||||
sys_execve("/sbin/login", &["/sbin/login", "/dev/ttyS0"]).unwrap();
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,6 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use libsys::{
|
||||
calls::{
|
||||
@ -96,7 +94,7 @@ fn login_as(uid: UserId, gid: GroupId, shell: &str) -> Result<(), Errno> {
|
||||
// TODO baud rate and misc port settings
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
if !sys_getuid().is_root() {
|
||||
if !sys_getuid().is_root() || !sys_getgid().is_root() {
|
||||
panic!("This program must be run as root");
|
||||
}
|
||||
|
||||
@ -143,9 +141,7 @@ fn main() -> i32 {
|
||||
.expect("Password read failed");
|
||||
|
||||
if username == "root" && password == "toor" {
|
||||
login_as(UserId::from(0), GroupId::from(0), "/bin/shell");
|
||||
login_as(UserId::from(0), GroupId::from(0), "/bin/shell").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user