|
@@ -1,6 +1,9 @@
|
|
|
use super::FromSyscallArg;
|
|
use super::FromSyscallArg;
|
|
|
-use crate::kernel::constants::{EINVAL, ENOMEM};
|
|
|
|
|
|
|
+use crate::fs::shm::{gen_shm_id, ShmFlags, IPC_PRIVATE, SHM_MANAGER};
|
|
|
|
|
+use crate::kernel::constants::{EBADF, EEXIST, EINVAL, ENOENT, ENOMEM};
|
|
|
|
|
+use crate::kernel::mem::FileMapping;
|
|
|
use crate::kernel::task::Thread;
|
|
use crate::kernel::task::Thread;
|
|
|
|
|
+use crate::kernel::vfs::filearray::FD;
|
|
|
use crate::{
|
|
use crate::{
|
|
|
kernel::{
|
|
kernel::{
|
|
|
constants::{UserMmapFlags, UserMmapProtocol},
|
|
constants::{UserMmapFlags, UserMmapProtocol},
|
|
@@ -26,8 +29,15 @@ impl FromSyscallArg for UserMmapFlags {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+impl FromSyscallArg for ShmFlags {
|
|
|
|
|
+ fn from_arg(value: usize) -> Self {
|
|
|
|
|
+ ShmFlags::from_bits_truncate(value as u32)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/// Check whether we are doing an implemented function.
|
|
/// Check whether we are doing an implemented function.
|
|
|
/// If `condition` is false, return `Err(err)`.
|
|
/// If `condition` is false, return `Err(err)`.
|
|
|
|
|
+#[allow(unused)]
|
|
|
fn check_impl(condition: bool, err: u32) -> KResult<()> {
|
|
fn check_impl(condition: bool, err: u32) -> KResult<()> {
|
|
|
if !condition {
|
|
if !condition {
|
|
|
Err(err)
|
|
Err(err)
|
|
@@ -42,60 +52,57 @@ fn do_mmap2(
|
|
|
len: usize,
|
|
len: usize,
|
|
|
prot: UserMmapProtocol,
|
|
prot: UserMmapProtocol,
|
|
|
flags: UserMmapFlags,
|
|
flags: UserMmapFlags,
|
|
|
- fd: u32,
|
|
|
|
|
|
|
+ fd: FD,
|
|
|
pgoffset: usize,
|
|
pgoffset: usize,
|
|
|
) -> KResult<usize> {
|
|
) -> KResult<usize> {
|
|
|
let addr = VAddr::from(addr);
|
|
let addr = VAddr::from(addr);
|
|
|
- if !addr.is_page_aligned() || len == 0 {
|
|
|
|
|
|
|
+ if !addr.is_page_aligned() || pgoffset % PAGE_SIZE != 0 || len == 0 {
|
|
|
return Err(EINVAL);
|
|
return Err(EINVAL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let len = len.align_up(PAGE_SIZE);
|
|
let len = len.align_up(PAGE_SIZE);
|
|
|
- check_impl(flags.contains(UserMmapFlags::MAP_ANONYMOUS), ENOMEM)?;
|
|
|
|
|
- check_impl(flags.contains(UserMmapFlags::MAP_PRIVATE), EINVAL)?;
|
|
|
|
|
- if fd != u32::MAX || pgoffset != 0 {
|
|
|
|
|
- return Err(EINVAL);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
let mm_list = &thread.process.mm_list;
|
|
let mm_list = &thread.process.mm_list;
|
|
|
|
|
+ let is_shared = flags.contains(UserMmapFlags::MAP_SHARED);
|
|
|
|
|
+
|
|
|
|
|
+ let mapping = if flags.contains(UserMmapFlags::MAP_ANONYMOUS) {
|
|
|
|
|
+ if pgoffset != 0 {
|
|
|
|
|
+ return Err(EINVAL);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if !is_shared {
|
|
|
|
|
+ Mapping::Anonymous
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // The mode is unimportant here, since we are checking prot in mm_area.
|
|
|
|
|
+ let shared_area = Task::block_on(SHM_MANAGER.lock()).create_shared_area(len, 0x777);
|
|
|
|
|
+ Mapping::File(FileMapping::new(shared_area.area.clone(), 0, len))
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ let file = thread
|
|
|
|
|
+ .files
|
|
|
|
|
+ .get(fd)
|
|
|
|
|
+ .ok_or(EBADF)?
|
|
|
|
|
+ .get_inode()?
|
|
|
|
|
+ .ok_or(EBADF)?;
|
|
|
|
|
+
|
|
|
|
|
+ Mapping::File(FileMapping::new(file, pgoffset, len))
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ let permission = Permission {
|
|
|
|
|
+ read: prot.contains(UserMmapProtocol::PROT_READ),
|
|
|
|
|
+ write: prot.contains(UserMmapProtocol::PROT_WRITE),
|
|
|
|
|
+ execute: prot.contains(UserMmapProtocol::PROT_EXEC),
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
// TODO!!!: If we are doing mmap's in 32-bit mode, we should check whether
|
|
// TODO!!!: If we are doing mmap's in 32-bit mode, we should check whether
|
|
|
// `addr` is above user reachable memory.
|
|
// `addr` is above user reachable memory.
|
|
|
let addr = if flags.contains(UserMmapFlags::MAP_FIXED) {
|
|
let addr = if flags.contains(UserMmapFlags::MAP_FIXED) {
|
|
|
if prot.is_empty() {
|
|
if prot.is_empty() {
|
|
|
- Task::block_on(mm_list.protect(
|
|
|
|
|
- addr,
|
|
|
|
|
- len,
|
|
|
|
|
- Permission {
|
|
|
|
|
- read: prot.contains(UserMmapProtocol::PROT_READ),
|
|
|
|
|
- write: prot.contains(UserMmapProtocol::PROT_WRITE),
|
|
|
|
|
- execute: prot.contains(UserMmapProtocol::PROT_EXEC),
|
|
|
|
|
- },
|
|
|
|
|
- ))
|
|
|
|
|
- .map(|_| addr)
|
|
|
|
|
|
|
+ Task::block_on(mm_list.protect(addr, len, permission)).map(|_| addr)
|
|
|
} else {
|
|
} else {
|
|
|
- mm_list.mmap_fixed(
|
|
|
|
|
- addr,
|
|
|
|
|
- len,
|
|
|
|
|
- Mapping::Anonymous,
|
|
|
|
|
- Permission {
|
|
|
|
|
- read: prot.contains(UserMmapProtocol::PROT_READ),
|
|
|
|
|
- write: prot.contains(UserMmapProtocol::PROT_WRITE),
|
|
|
|
|
- execute: prot.contains(UserMmapProtocol::PROT_EXEC),
|
|
|
|
|
- },
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ mm_list.mmap_fixed(addr, len, mapping, permission, is_shared)
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- mm_list.mmap_hint(
|
|
|
|
|
- addr,
|
|
|
|
|
- len,
|
|
|
|
|
- Mapping::Anonymous,
|
|
|
|
|
- Permission {
|
|
|
|
|
- read: prot.contains(UserMmapProtocol::PROT_READ),
|
|
|
|
|
- write: prot.contains(UserMmapProtocol::PROT_WRITE),
|
|
|
|
|
- execute: prot.contains(UserMmapProtocol::PROT_EXEC),
|
|
|
|
|
- },
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ mm_list.mmap_hint(addr, len, mapping, permission, is_shared)
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
addr.map(|addr| addr.addr())
|
|
addr.map(|addr| addr.addr())
|
|
@@ -108,7 +115,7 @@ fn mmap(
|
|
|
len: usize,
|
|
len: usize,
|
|
|
prot: UserMmapProtocol,
|
|
prot: UserMmapProtocol,
|
|
|
flags: UserMmapFlags,
|
|
flags: UserMmapFlags,
|
|
|
- fd: u32,
|
|
|
|
|
|
|
+ fd: FD,
|
|
|
offset: usize,
|
|
offset: usize,
|
|
|
) -> KResult<usize> {
|
|
) -> KResult<usize> {
|
|
|
do_mmap2(thread, addr, len, prot, flags, fd, offset / PAGE_SIZE)
|
|
do_mmap2(thread, addr, len, prot, flags, fd, offset / PAGE_SIZE)
|
|
@@ -121,7 +128,7 @@ fn mmap2(
|
|
|
len: usize,
|
|
len: usize,
|
|
|
prot: UserMmapProtocol,
|
|
prot: UserMmapProtocol,
|
|
|
flags: UserMmapFlags,
|
|
flags: UserMmapFlags,
|
|
|
- fd: u32,
|
|
|
|
|
|
|
+ fd: FD,
|
|
|
pgoffset: usize,
|
|
pgoffset: usize,
|
|
|
) -> KResult<usize> {
|
|
) -> KResult<usize> {
|
|
|
do_mmap2(thread, addr, len, prot, flags, fd, pgoffset)
|
|
do_mmap2(thread, addr, len, prot, flags, fd, pgoffset)
|
|
@@ -169,6 +176,85 @@ fn mprotect(addr: usize, len: usize, prot: UserMmapProtocol) -> KResult<()> {
|
|
|
))
|
|
))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#[eonix_macros::define_syscall(SYS_SHMGET)]
|
|
|
|
|
+fn shmget(key: usize, size: usize, shmflg: ShmFlags) -> KResult<u32> {
|
|
|
|
|
+ let size = size.align_up(PAGE_SIZE);
|
|
|
|
|
+
|
|
|
|
|
+ let mut shm_manager = Task::block_on(SHM_MANAGER.lock());
|
|
|
|
|
+ let shmid = gen_shm_id(key)?;
|
|
|
|
|
+
|
|
|
|
|
+ if key == IPC_PRIVATE {
|
|
|
|
|
+ let new_shm = shm_manager.create_shared_area(size, shmflg.bits() & 0x777);
|
|
|
|
|
+ shm_manager.insert(shmid, new_shm);
|
|
|
|
|
+ return Ok(shmid);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if let Some(_) = shm_manager.get(shmid) {
|
|
|
|
|
+ if shmflg.contains(ShmFlags::IPC_CREAT | ShmFlags::IPC_EXCL) {
|
|
|
|
|
+ return Err(EEXIST);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Ok(shmid);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if shmflg.contains(ShmFlags::IPC_CREAT) {
|
|
|
|
|
+ let new_shm = shm_manager.create_shared_area(size, shmflg.bits() & 0x777);
|
|
|
|
|
+ shm_manager.insert(shmid, new_shm);
|
|
|
|
|
+ return Ok(shmid);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Err(ENOENT);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#[eonix_macros::define_syscall(SYS_SHMAT)]
|
|
|
|
|
+fn shmat(shmid: u32, addr: usize, shmflg: ShmFlags) -> KResult<usize> {
|
|
|
|
|
+ let mm_list = &thread.process.mm_list;
|
|
|
|
|
+ let shm_manager = Task::block_on(SHM_MANAGER.lock());
|
|
|
|
|
+ let shm_area = shm_manager.get(shmid).ok_or(EINVAL)?;
|
|
|
|
|
+
|
|
|
|
|
+ let mut permission = Permission {
|
|
|
|
|
+ read: true,
|
|
|
|
|
+ write: true,
|
|
|
|
|
+ execute: false,
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if shmflg.contains(ShmFlags::SHM_EXEC) {
|
|
|
|
|
+ permission.execute = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if shmflg.contains(ShmFlags::SHM_RDONLY) {
|
|
|
|
|
+ permission.write = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let mapping = Mapping::File(FileMapping {
|
|
|
|
|
+ file: shm_area.area.clone(),
|
|
|
|
|
+ offset: 0,
|
|
|
|
|
+ length: shm_area.size,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ let addr = if addr != 0 {
|
|
|
|
|
+ if addr % PAGE_SIZE != 0 && !shmflg.contains(ShmFlags::SHM_RND) {
|
|
|
|
|
+ return Err(EINVAL);
|
|
|
|
|
+ }
|
|
|
|
|
+ let addr = VAddr::from(addr.align_down(PAGE_SIZE));
|
|
|
|
|
+ mm_list.mmap_fixed(addr, shm_area.size, mapping, permission, true)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mm_list.mmap_hint(VAddr::NULL, shm_area.size, mapping, permission, true)
|
|
|
|
|
+ }?;
|
|
|
|
|
+
|
|
|
|
|
+ thread.process.shm_areas.lock().insert(addr, shm_area.size);
|
|
|
|
|
+
|
|
|
|
|
+ Ok(addr.addr())
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#[eonix_macros::define_syscall(SYS_SHMDT)]
|
|
|
|
|
+fn shmdt(addr: usize) -> KResult<usize> {
|
|
|
|
|
+ let addr = VAddr::from(addr);
|
|
|
|
|
+ let mut shm_areas = thread.process.shm_areas.lock();
|
|
|
|
|
+ let size = *shm_areas.get(&addr).ok_or(EINVAL)?;
|
|
|
|
|
+ shm_areas.remove(&addr);
|
|
|
|
|
+ return Task::block_on(thread.process.mm_list.unmap(addr, size)).map(|_| 0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#[eonix_macros::define_syscall(SYS_MEMBARRIER)]
|
|
#[eonix_macros::define_syscall(SYS_MEMBARRIER)]
|
|
|
fn membarrier(_cmd: usize, _flags: usize) -> KResult<()> {
|
|
fn membarrier(_cmd: usize, _flags: usize) -> KResult<()> {
|
|
|
Ok(())
|
|
Ok(())
|