mirror of
https://github.com/obhq/obliteration.git
synced 2025-02-22 04:41:44 +00:00
Moves sys_cpuset_getaffinity to ProcManager (#868)
This commit is contained in:
parent
e23ba2b76d
commit
404587185d
@ -1,4 +1,5 @@
|
||||
use crate::{errno::EINVAL, syscalls::SysErr};
|
||||
use crate::errno::EINVAL;
|
||||
use crate::syscalls::{SysArg, SysErr};
|
||||
|
||||
/// An implementation of `cpuset`.
|
||||
#[derive(Debug)]
|
||||
@ -24,30 +25,40 @@ pub struct CpuMask {
|
||||
}
|
||||
|
||||
/// An implementation of `cpulevel_t`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum CpuLevel {
|
||||
Root = 1,
|
||||
Cpuset = 2,
|
||||
Which = 3,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for CpuLevel {
|
||||
impl CpuLevel {
|
||||
pub fn new(v: i32) -> Option<Self> {
|
||||
Some(match v {
|
||||
1 => Self::Root,
|
||||
2 => Self::Cpuset,
|
||||
3 => Self::Which,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SysArg> for CpuLevel {
|
||||
type Error = SysErr;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
1 => Ok(Self::Root),
|
||||
2 => Ok(Self::Cpuset),
|
||||
3 => Ok(Self::Which),
|
||||
_ => Err(SysErr::Raw(EINVAL)),
|
||||
}
|
||||
fn try_from(value: SysArg) -> Result<Self, Self::Error> {
|
||||
value
|
||||
.try_into()
|
||||
.ok()
|
||||
.and_then(|v| Self::new(v))
|
||||
.ok_or(SysErr::Raw(EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation of `cpuwhich_t`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum CpuWhich {
|
||||
Tid = 1,
|
||||
Pid = 2,
|
||||
@ -56,17 +67,27 @@ pub(super) enum CpuWhich {
|
||||
Jail = 5,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for CpuWhich {
|
||||
type Error = SysErr;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
1 => Ok(Self::Tid),
|
||||
2 => Ok(Self::Pid),
|
||||
3 => Ok(Self::Cpuset),
|
||||
4 => Ok(Self::Irq),
|
||||
5 => Ok(Self::Jail),
|
||||
_ => Err(SysErr::Raw(EINVAL)),
|
||||
}
|
||||
impl CpuWhich {
|
||||
pub fn new(v: i32) -> Option<Self> {
|
||||
Some(match v {
|
||||
1 => Self::Tid,
|
||||
2 => Self::Pid,
|
||||
3 => Self::Cpuset,
|
||||
4 => Self::Irq,
|
||||
5 => Self::Jail,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SysArg> for CpuWhich {
|
||||
type Error = SysErr;
|
||||
|
||||
fn try_from(value: SysArg) -> Result<Self, Self::Error> {
|
||||
value
|
||||
.try_into()
|
||||
.ok()
|
||||
.and_then(|v| Self::new(v))
|
||||
.ok_or(SysErr::Raw(EINVAL))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::budget::ProcType;
|
||||
use crate::dev::DmemContainer;
|
||||
use crate::errno::{EINVAL, ENAMETOOLONG, EPERM, ESRCH};
|
||||
use crate::errno::{EINVAL, ENAMETOOLONG, EPERM, ERANGE, ESRCH};
|
||||
use crate::fs::{Fs, Vnode};
|
||||
use crate::info;
|
||||
use crate::rcmgr::RcMgr;
|
||||
@ -67,6 +67,7 @@ impl ProcManager {
|
||||
sys.register(416, &mgr, Self::sys_sigaction);
|
||||
sys.register(432, &mgr, Self::sys_thr_self);
|
||||
sys.register(464, &mgr, Self::sys_thr_set_name);
|
||||
sys.register(487, &mgr, Self::sys_cpuset_getaffinity);
|
||||
sys.register(585, &mgr, Self::sys_is_in_sandbox);
|
||||
sys.register(587, &mgr, Self::sys_get_authinfo);
|
||||
sys.register(602, &mgr, Self::sys_randomized_path);
|
||||
@ -335,6 +336,50 @@ impl ProcManager {
|
||||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
fn sys_cpuset_getaffinity(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
// Get arguments.
|
||||
let level: CpuLevel = i.args[0].try_into()?;
|
||||
let which: CpuWhich = i.args[1].try_into()?;
|
||||
let id: i64 = i.args[2].into();
|
||||
let cpusetsize: usize = i.args[3].into();
|
||||
let mask: *mut u8 = i.args[4].into();
|
||||
|
||||
// TODO: Refactor this for readability.
|
||||
if cpusetsize.wrapping_sub(8) > 8 {
|
||||
return Err(SysErr::Raw(ERANGE));
|
||||
}
|
||||
|
||||
let (_, td) = self.cpuset_which(which, id)?;
|
||||
let mut buf = vec![0u8; cpusetsize];
|
||||
|
||||
match level {
|
||||
CpuLevel::Which => match which {
|
||||
CpuWhich::Tid => {
|
||||
let v = td.cpuset().mask().bits[0].to_ne_bytes();
|
||||
buf[..v.len()].copy_from_slice(&v);
|
||||
}
|
||||
v => todo!("sys_cpuset_getaffinity with which = {v:?}"),
|
||||
},
|
||||
v => todo!("sys_cpuset_getaffinity with level = {v:?}"),
|
||||
}
|
||||
|
||||
// TODO: What is this?
|
||||
let x = u32::from_ne_bytes(buf[..4].try_into().unwrap());
|
||||
let y = (x >> 1 & 0x55) + (x & 0x55) * 2;
|
||||
let z = (y >> 2 & 0xfffffff3) + (y & 0x33) * 4;
|
||||
|
||||
unsafe {
|
||||
std::ptr::write_unaligned::<u64>(
|
||||
buf.as_mut_ptr() as _,
|
||||
(z >> 4 | (z & 0xf) << 4) as u64,
|
||||
);
|
||||
|
||||
std::ptr::copy_nonoverlapping(buf.as_ptr(), mask, cpusetsize);
|
||||
}
|
||||
|
||||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
fn sys_is_in_sandbox(self: &Arc<Self>, td: &VThread, _: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let v = !Arc::ptr_eq(&td.proc().files().root(), &self.fs.root());
|
||||
|
||||
@ -480,6 +525,67 @@ impl ProcManager {
|
||||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
/// See `cpuset_which` on the PS4 for a reference.
|
||||
fn cpuset_which(&self, which: CpuWhich, id: i64) -> Result<(Arc<VProc>, Arc<VThread>), SysErr> {
|
||||
// Get process and thread.
|
||||
let (p, td) = match which {
|
||||
CpuWhich::Tid => {
|
||||
let td = if id == -1 {
|
||||
VThread::current().unwrap().clone()
|
||||
} else {
|
||||
id.try_into()
|
||||
.ok()
|
||||
.and_then(|id| NonZeroI32::new(id))
|
||||
.and_then(|id| self.thread(id, None))
|
||||
.ok_or(SysErr::Raw(ESRCH))?
|
||||
};
|
||||
|
||||
(td.proc().clone(), Some(td))
|
||||
}
|
||||
v => todo!("cpuset_which with which = {v:?}"),
|
||||
};
|
||||
|
||||
// Check if the calling thread can reschedule the process.
|
||||
VThread::current().unwrap().can_sched(&p)?;
|
||||
|
||||
match td {
|
||||
Some(td) => Ok((p, td)),
|
||||
None => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// See `tdfind` on the PS4 for a reference.
|
||||
fn thread(&self, tid: NonZeroI32, pid: Option<Pid>) -> Option<Arc<VThread>> {
|
||||
// TODO: Use a proper implementation.
|
||||
match pid {
|
||||
Some(pid) => {
|
||||
let proc = self
|
||||
.list
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&pid)
|
||||
.and_then(|p| p.upgrade())?;
|
||||
let threads = proc.threads();
|
||||
|
||||
threads.iter().find(|&t| t.id() == tid).cloned()
|
||||
}
|
||||
None => {
|
||||
let procs = self.list.read().unwrap();
|
||||
|
||||
for p in procs.values().map(|p| p.upgrade()).filter_map(|i| i) {
|
||||
let threads = p.threads();
|
||||
let found = threads.iter().find(|&t| t.id() == tid).cloned();
|
||||
|
||||
if found.is_some() {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_id() -> NonZeroI32 {
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
|
@ -94,7 +94,6 @@ impl VProc {
|
||||
// TODO: Move all syscalls here to somewhere else.
|
||||
sys.register(455, &vp, Self::sys_thr_new);
|
||||
sys.register(466, &vp, Self::sys_rtprio_thread);
|
||||
sys.register(487, &vp, Self::sys_cpuset_getaffinity);
|
||||
sys.register(488, &vp, Self::sys_cpuset_setaffinity);
|
||||
|
||||
vp.abi.set(ProcAbi::new(sys)).unwrap();
|
||||
@ -273,53 +272,9 @@ impl VProc {
|
||||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
fn sys_cpuset_getaffinity(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
// Get arguments.
|
||||
let level: CpuLevel = TryInto::<i32>::try_into(i.args[0]).unwrap().try_into()?;
|
||||
let which: CpuWhich = TryInto::<i32>::try_into(i.args[1]).unwrap().try_into()?;
|
||||
let id: i64 = i.args[2].into();
|
||||
let cpusetsize: usize = i.args[3].into();
|
||||
let mask: *mut u8 = i.args[4].into();
|
||||
|
||||
// TODO: Refactor this for readability.
|
||||
if cpusetsize.wrapping_sub(8) > 8 {
|
||||
return Err(SysErr::Raw(ERANGE));
|
||||
}
|
||||
|
||||
let td = self.cpuset_which(which, id)?;
|
||||
let mut buf = vec![0u8; cpusetsize];
|
||||
|
||||
match level {
|
||||
CpuLevel::Which => match which {
|
||||
CpuWhich::Tid => {
|
||||
let v = td.cpuset().mask().bits[0].to_ne_bytes();
|
||||
buf[..v.len()].copy_from_slice(&v);
|
||||
}
|
||||
v => todo!("sys_cpuset_getaffinity with which = {v:?}"),
|
||||
},
|
||||
v => todo!("sys_cpuset_getaffinity with level = {v:?}"),
|
||||
}
|
||||
|
||||
// TODO: What is this?
|
||||
let x = u32::from_ne_bytes(buf[..4].try_into().unwrap());
|
||||
let y = (x >> 1 & 0x55) + (x & 0x55) * 2;
|
||||
let z = (y >> 2 & 0xfffffff3) + (y & 0x33) * 4;
|
||||
|
||||
unsafe {
|
||||
std::ptr::write_unaligned::<u64>(
|
||||
buf.as_mut_ptr() as _,
|
||||
(z >> 4 | (z & 0xf) << 4) as u64,
|
||||
);
|
||||
|
||||
std::ptr::copy_nonoverlapping(buf.as_ptr(), mask, cpusetsize);
|
||||
}
|
||||
|
||||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
fn sys_cpuset_setaffinity(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let level: CpuLevel = TryInto::<i32>::try_into(i.args[0]).unwrap().try_into()?;
|
||||
let which: CpuWhich = TryInto::<i32>::try_into(i.args[1]).unwrap().try_into()?;
|
||||
let level: CpuLevel = i.args[0].try_into()?;
|
||||
let which: CpuWhich = i.args[1].try_into()?;
|
||||
let _id: i64 = i.args[2].into();
|
||||
let cpusetsize: usize = i.args[3].into();
|
||||
let _mask: *const u8 = i.args[4].into();
|
||||
@ -339,32 +294,6 @@ impl VProc {
|
||||
v => todo!("sys_cpuset_setaffinity with level = {v:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// See `cpuset_which` on the PS4 for a reference.
|
||||
fn cpuset_which(&self, which: CpuWhich, id: i64) -> Result<Arc<VThread>, SysErr> {
|
||||
let td = match which {
|
||||
CpuWhich::Tid => {
|
||||
if id == -1 {
|
||||
todo!("cpuset_which with id = -1");
|
||||
} else {
|
||||
let threads = self.threads.read();
|
||||
let td = threads
|
||||
.iter()
|
||||
.find(|t| t.id().get() == id as i32)
|
||||
.ok_or(SysErr::Raw(ESRCH))?
|
||||
.clone();
|
||||
|
||||
Some(td)
|
||||
}
|
||||
}
|
||||
v => todo!("cpuset_which with which = {v:?}"),
|
||||
};
|
||||
|
||||
match td {
|
||||
Some(v) => Ok(v),
|
||||
None => todo!("cpuset_which with td = NULL"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -107,6 +107,17 @@ impl VThread {
|
||||
self.cred.priv_check(p)
|
||||
}
|
||||
|
||||
/// Determine whether current thread may reschedule `p`.
|
||||
///
|
||||
/// See `p_cansched` on the PS4 for a reference.
|
||||
pub fn can_sched(&self, p: &Arc<VProc>) -> Result<(), CanSchedError> {
|
||||
if Arc::ptr_eq(&self.proc, p) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Start the thread.
|
||||
///
|
||||
/// The caller is responsible for `stack` deallocation.
|
||||
@ -185,7 +196,8 @@ impl Drop for Running {
|
||||
}
|
||||
}
|
||||
|
||||
static VTHREAD: Tls<Arc<VThread>> = Tls::new();
|
||||
|
||||
/// Represents an error when [`VThread::can_sched()`] fails.
|
||||
#[derive(Debug, Error, Errno)]
|
||||
pub enum FileAllocError {}
|
||||
pub enum CanSchedError {}
|
||||
|
||||
static VTHREAD: Tls<Arc<VThread>> = Tls::new();
|
||||
|
Loading…
x
Reference in New Issue
Block a user