mm.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. use super::FromSyscallArg;
  2. use crate::fs::shm::{gen_shm_id, ShmFlags, IPC_PRIVATE, SHM_MANAGER};
  3. use crate::kernel::constants::{EBADF, EEXIST, EINVAL, ENOENT, ENOMEM};
  4. use crate::kernel::mem::FileMapping;
  5. use crate::kernel::task::Thread;
  6. use crate::kernel::vfs::filearray::FD;
  7. use crate::{
  8. kernel::{
  9. constants::{UserMmapFlags, UserMmapProtocol},
  10. mem::{Mapping, Permission},
  11. },
  12. prelude::*,
  13. };
  14. use align_ext::AlignExt;
  15. use eonix_mm::address::{Addr as _, AddrOps as _, VAddr};
  16. use eonix_mm::paging::PAGE_SIZE;
  17. use eonix_runtime::task::Task;
  18. use posix_types::syscall_no::*;
  19. impl FromSyscallArg for UserMmapProtocol {
  20. fn from_arg(value: usize) -> UserMmapProtocol {
  21. UserMmapProtocol::from_bits_truncate(value as u32)
  22. }
  23. }
  24. impl FromSyscallArg for UserMmapFlags {
  25. fn from_arg(value: usize) -> UserMmapFlags {
  26. UserMmapFlags::from_bits_truncate(value as u32)
  27. }
  28. }
  29. /// Check whether we are doing an implemented function.
  30. /// If `condition` is false, return `Err(err)`.
  31. #[allow(unused)]
  32. fn check_impl(condition: bool, err: u32) -> KResult<()> {
  33. if !condition {
  34. Err(err)
  35. } else {
  36. Ok(())
  37. }
  38. }
  39. fn do_mmap2(
  40. thread: &Thread,
  41. addr: usize,
  42. len: usize,
  43. prot: UserMmapProtocol,
  44. flags: UserMmapFlags,
  45. fd: FD,
  46. pgoffset: usize,
  47. ) -> KResult<usize> {
  48. let addr = VAddr::from(addr);
  49. if !addr.is_page_aligned() || pgoffset % PAGE_SIZE != 0 || len == 0 {
  50. return Err(EINVAL);
  51. }
  52. let len = len.align_up(PAGE_SIZE);
  53. let mm_list = &thread.process.mm_list;
  54. let is_shared = flags.contains(UserMmapFlags::MAP_SHARED);
  55. let mapping = if flags.contains(UserMmapFlags::MAP_ANONYMOUS) {
  56. if pgoffset != 0 {
  57. return Err(EINVAL);
  58. }
  59. if !is_shared {
  60. Mapping::Anonymous
  61. } else {
  62. // The mode is unimportant here, since we are checking prot in mm_area.
  63. let shared_area = Task::block_on(SHM_MANAGER.lock()).create_shared_area(
  64. len,
  65. thread.process.pid,
  66. 0x777,
  67. );
  68. Mapping::File(FileMapping::new(shared_area.area.clone(), 0, len))
  69. }
  70. } else {
  71. let file = thread
  72. .files
  73. .get(fd)
  74. .ok_or(EBADF)?
  75. .get_inode()?
  76. .ok_or(EBADF)?;
  77. Mapping::File(FileMapping::new(file, pgoffset, len))
  78. };
  79. let permission = Permission {
  80. read: prot.contains(UserMmapProtocol::PROT_READ),
  81. write: prot.contains(UserMmapProtocol::PROT_WRITE),
  82. execute: prot.contains(UserMmapProtocol::PROT_EXEC),
  83. };
  84. // TODO!!!: If we are doing mmap's in 32-bit mode, we should check whether
  85. // `addr` is above user reachable memory.
  86. let addr = if flags.contains(UserMmapFlags::MAP_FIXED) {
  87. Task::block_on(mm_list.unmap(addr, len));
  88. mm_list.mmap_fixed(addr, len, mapping, permission, is_shared)
  89. } else {
  90. mm_list.mmap_hint(addr, len, mapping, permission, is_shared)
  91. };
  92. addr.map(|addr| addr.addr())
  93. }
  94. #[cfg(any(target_arch = "riscv64", target_arch = "loongarch64"))]
  95. #[eonix_macros::define_syscall(SYS_MMAP)]
  96. fn mmap(
  97. addr: usize,
  98. len: usize,
  99. prot: UserMmapProtocol,
  100. flags: UserMmapFlags,
  101. fd: FD,
  102. offset: usize,
  103. ) -> KResult<usize> {
  104. do_mmap2(thread, addr, len, prot, flags, fd, offset)
  105. }
  106. #[cfg(target_arch = "x86_64")]
  107. #[eonix_macros::define_syscall(SYS_MMAP2)]
  108. fn mmap2(
  109. addr: usize,
  110. len: usize,
  111. prot: UserMmapProtocol,
  112. flags: UserMmapFlags,
  113. fd: FD,
  114. pgoffset: usize,
  115. ) -> KResult<usize> {
  116. do_mmap2(thread, addr, len, prot, flags, fd, pgoffset)
  117. }
  118. #[eonix_macros::define_syscall(SYS_MUNMAP)]
  119. fn munmap(addr: usize, len: usize) -> KResult<usize> {
  120. let addr = VAddr::from(addr);
  121. if !addr.is_page_aligned() || len == 0 {
  122. return Err(EINVAL);
  123. }
  124. let len = len.align_up(PAGE_SIZE);
  125. Task::block_on(thread.process.mm_list.unmap(addr, len)).map(|_| 0)
  126. }
  127. #[eonix_macros::define_syscall(SYS_BRK)]
  128. fn brk(addr: usize) -> KResult<usize> {
  129. let vaddr = if addr == 0 { None } else { Some(VAddr::from(addr)) };
  130. Ok(thread.process.mm_list.set_break(vaddr).addr())
  131. }
  132. #[eonix_macros::define_syscall(SYS_MADVISE)]
  133. fn madvise(_addr: usize, _len: usize, _advice: u32) -> KResult<()> {
  134. Ok(())
  135. }
  136. #[eonix_macros::define_syscall(SYS_MPROTECT)]
  137. fn mprotect(addr: usize, len: usize, prot: UserMmapProtocol) -> KResult<()> {
  138. let addr = VAddr::from(addr);
  139. if !addr.is_page_aligned() || len == 0 {
  140. return Err(EINVAL);
  141. }
  142. let len = len.align_up(PAGE_SIZE);
  143. Task::block_on(thread.process.mm_list.protect(
  144. addr,
  145. len,
  146. Permission {
  147. read: prot.contains(UserMmapProtocol::PROT_READ),
  148. write: prot.contains(UserMmapProtocol::PROT_WRITE),
  149. execute: prot.contains(UserMmapProtocol::PROT_EXEC),
  150. },
  151. ))
  152. }
  153. #[eonix_macros::define_syscall(SYS_SHMGET)]
  154. fn shmget(key: usize, size: usize, shmflg: u32) -> KResult<u32> {
  155. let size = size.align_up(PAGE_SIZE);
  156. let mut shm_manager = Task::block_on(SHM_MANAGER.lock());
  157. let shmid = gen_shm_id(key)?;
  158. let mode = shmflg & 0o777;
  159. let shmflg = ShmFlags::from_bits_truncate(shmflg);
  160. if key == IPC_PRIVATE {
  161. let new_shm = shm_manager.create_shared_area(size, thread.process.pid, mode);
  162. shm_manager.insert(shmid, new_shm);
  163. return Ok(shmid);
  164. }
  165. if let Some(_) = shm_manager.get(shmid) {
  166. if shmflg.contains(ShmFlags::IPC_CREAT | ShmFlags::IPC_EXCL) {
  167. return Err(EEXIST);
  168. }
  169. return Ok(shmid);
  170. }
  171. if shmflg.contains(ShmFlags::IPC_CREAT) {
  172. let new_shm = shm_manager.create_shared_area(size, thread.process.pid, mode);
  173. shm_manager.insert(shmid, new_shm);
  174. return Ok(shmid);
  175. }
  176. return Err(ENOENT);
  177. }
  178. #[eonix_macros::define_syscall(SYS_SHMAT)]
  179. fn shmat(shmid: u32, addr: usize, shmflg: u32) -> KResult<usize> {
  180. let mm_list = &thread.process.mm_list;
  181. let shm_manager = Task::block_on(SHM_MANAGER.lock());
  182. let shm_area = shm_manager.get(shmid).ok_or(EINVAL)?;
  183. let mode = shmflg & 0o777;
  184. let shmflg = ShmFlags::from_bits_truncate(shmflg);
  185. let mut permission = Permission {
  186. read: true,
  187. write: true,
  188. execute: false,
  189. };
  190. if shmflg.contains(ShmFlags::SHM_EXEC) {
  191. permission.execute = true;
  192. }
  193. if shmflg.contains(ShmFlags::SHM_RDONLY) {
  194. permission.write = false;
  195. }
  196. let size = shm_area.shmid_ds.shm_segsz;
  197. let mapping = Mapping::File(FileMapping {
  198. file: shm_area.area.clone(),
  199. offset: 0,
  200. length: size,
  201. });
  202. let addr = if addr != 0 {
  203. if addr % PAGE_SIZE != 0 && !shmflg.contains(ShmFlags::SHM_RND) {
  204. return Err(EINVAL);
  205. }
  206. let addr = VAddr::from(addr.align_down(PAGE_SIZE));
  207. mm_list.mmap_fixed(addr, size, mapping, permission, true)
  208. } else {
  209. mm_list.mmap_hint(VAddr::NULL, size, mapping, permission, true)
  210. }?;
  211. thread.process.shm_areas.lock().insert(addr, size);
  212. Ok(addr.addr())
  213. }
  214. #[eonix_macros::define_syscall(SYS_SHMDT)]
  215. fn shmdt(addr: usize) -> KResult<usize> {
  216. let addr = VAddr::from(addr);
  217. let mut shm_areas = thread.process.shm_areas.lock();
  218. let size = *shm_areas.get(&addr).ok_or(EINVAL)?;
  219. shm_areas.remove(&addr);
  220. drop(shm_areas);
  221. return Task::block_on(thread.process.mm_list.unmap(addr, size)).map(|_| 0);
  222. }
  223. #[eonix_macros::define_syscall(SYS_SHMCTL)]
  224. fn shmctl(shmid: u32, op: i32, shmid_ds: usize) -> KResult<usize> {
  225. Ok(0)
  226. }
  227. #[eonix_macros::define_syscall(SYS_MEMBARRIER)]
  228. fn membarrier(_cmd: usize, _flags: usize) -> KResult<()> {
  229. Ok(())
  230. }
  231. pub fn keep_alive() {}