1use crate::mm::barrier::{BarrierType, system_barrier};
6use crate::mm::debugger::notify_debugger_of_module_list;
7use crate::mm::{
8 DesiredAddress, FutexKey, IOVecPtr, MappingName, MappingOptions, MembarrierType,
9 MemoryAccessorExt, MremapFlags, MsyncFlags, PAGE_SIZE, PrivateFutexKey, ProtectionFlags,
10 SharedFutexKey,
11};
12use crate::security;
13use crate::syscalls::time::TimeSpecPtr;
14use crate::task::{CurrentTask, ProcessEntryRef};
15use crate::time::TargetTime;
16use crate::time::utc::estimate_boot_deadline_from_utc;
17use crate::vfs::buffers::{OutputBuffer, UserBuffersInputBuffer, UserBuffersOutputBuffer};
18use crate::vfs::{FdNumber, PidFdFileObject};
19use fuchsia_runtime::UtcTimeline;
20use linux_uapi::MLOCK_ONFAULT;
21use starnix_logging::{CATEGORY_STARNIX_MM, log_trace, track_stub};
22use starnix_syscalls::SyscallArg;
23use starnix_types::time::{duration_from_timespec, time_from_timespec};
24use starnix_uapi::auth::{PTRACE_MODE_ATTACH_REALCREDS, PTRACE_MODE_READ_REALCREDS};
25use starnix_uapi::errors::{EINTR, Errno};
26use starnix_uapi::personality::PersonalityFlags;
27use starnix_uapi::user_address::{UserAddress, UserRef};
28use starnix_uapi::user_value::UserValue;
29use starnix_uapi::{
30 FUTEX_BITSET_MATCH_ANY, FUTEX_CLOCK_REALTIME, FUTEX_CMD_MASK, FUTEX_CMP_REQUEUE,
31 FUTEX_CMP_REQUEUE_PI, FUTEX_LOCK_PI, FUTEX_LOCK_PI2, FUTEX_PRIVATE_FLAG, FUTEX_REQUEUE,
32 FUTEX_TRYLOCK_PI, FUTEX_UNLOCK_PI, FUTEX_WAIT, FUTEX_WAIT_BITSET, FUTEX_WAIT_REQUEUE_PI,
33 FUTEX_WAKE, FUTEX_WAKE_BITSET, FUTEX_WAKE_OP, MAP_ANONYMOUS, MAP_DENYWRITE, MAP_FIXED,
34 MAP_FIXED_NOREPLACE, MAP_GROWSDOWN, MAP_LOCKED, MAP_NORESERVE, MAP_POPULATE, MAP_PRIVATE,
35 MAP_SHARED, MAP_SHARED_VALIDATE, MAP_STACK, PROT_EXEC, errno, error, robust_list_head, tid_t,
36 uapi,
37};
38use std::ops::Deref as _;
39use zx;
40
41#[cfg(target_arch = "x86_64")]
42use starnix_uapi::MAP_32BIT;
43
44#[cfg(target_arch = "x86_64")]
47fn get_valid_platform_mmap_flags() -> u32 {
48 MAP_32BIT
49}
50#[cfg(not(target_arch = "x86_64"))]
51fn get_valid_platform_mmap_flags() -> u32 {
52 0
53}
54
55pub fn sys_mmap(
57 current_task: &mut CurrentTask,
58 addr: UserAddress,
59 length: usize,
60 prot: u32,
61 flags: u32,
62 fd: FdNumber,
63 offset: u64,
64) -> Result<UserAddress, Errno> {
65 let user_address = do_mmap(current_task, addr, length, prot, flags, fd, offset)?;
66 if prot & PROT_EXEC != 0 {
69 notify_debugger_of_module_list(current_task)?;
73 }
74 Ok(user_address)
75}
76
77fn read_implies_exec(current_task: &CurrentTask) -> bool {
88 current_task.thread_group().read().personality.contains(PersonalityFlags::READ_IMPLIES_EXEC)
89}
90
91pub fn do_mmap(
92 current_task: &CurrentTask,
93 addr: UserAddress,
94 length: usize,
95 prot: u32,
96 flags: u32,
97 fd: FdNumber,
98 offset: u64,
99) -> Result<UserAddress, Errno> {
100 let mut prot_flags = ProtectionFlags::from_access_bits(prot).ok_or_else(|| {
101 track_stub!(TODO("https://fxbug.dev/322874211"), "mmap parse protection", prot);
102 errno!(EINVAL)
103 })?;
104
105 let valid_flags: u32 = get_valid_platform_mmap_flags()
106 | MAP_PRIVATE
107 | MAP_SHARED
108 | MAP_SHARED_VALIDATE
109 | MAP_ANONYMOUS
110 | MAP_FIXED
111 | MAP_FIXED_NOREPLACE
112 | MAP_POPULATE
113 | MAP_NORESERVE
114 | MAP_STACK
115 | MAP_DENYWRITE
116 | MAP_GROWSDOWN
117 | MAP_LOCKED;
118 if flags & !valid_flags != 0 {
119 if flags & MAP_SHARED_VALIDATE != 0 {
120 return error!(EOPNOTSUPP);
121 }
122 track_stub!(TODO("https://fxbug.dev/322873638"), "mmap check flags", flags);
123 return error!(EINVAL);
124 }
125
126 let file = if flags & MAP_ANONYMOUS != 0 { None } else { Some(current_task.files().get(fd)?) };
127
128 if prot_flags.contains(ProtectionFlags::READ)
132 && read_implies_exec(current_task)
133 && file.as_ref().is_none_or(|file| file.can_exec() && file.ops().can_map_executable())
134 {
135 prot_flags |= ProtectionFlags::EXEC;
136 }
137
138 if flags & (MAP_PRIVATE | MAP_SHARED) == 0
139 || flags & (MAP_PRIVATE | MAP_SHARED) == MAP_PRIVATE | MAP_SHARED
140 {
141 return error!(EINVAL);
142 }
143 if length == 0 {
144 return error!(EINVAL);
145 }
146 if offset % *PAGE_SIZE != 0 {
147 return error!(EINVAL);
148 }
149
150 let page_size = *PAGE_SIZE as usize;
151 let length_aligned =
152 length.checked_add(page_size - 1).ok_or_else(|| errno!(ENOMEM))? & !(page_size - 1);
153 let rlimit_as = current_task
154 .thread_group()
155 .get_rlimit(starnix_uapi::resource_limits::Resource::AS) as usize;
156 let current_usage: usize = current_task.mm()?.get_total_usage();
157
158 if current_usage.saturating_add(length_aligned) > rlimit_as {
159 return error!(ENOMEM);
160 }
161
162 let addr = match (addr, flags & MAP_FIXED != 0, flags & MAP_FIXED_NOREPLACE != 0) {
165 (UserAddress::NULL, false, false) => DesiredAddress::Any,
166 (UserAddress::NULL, true, _) | (UserAddress::NULL, _, true) => return error!(EINVAL),
167 (addr, false, false) => DesiredAddress::Hint(addr),
168 (addr, _, true) => DesiredAddress::Fixed(addr),
169 (addr, true, false) => DesiredAddress::FixedOverwrite(addr),
170 };
171
172 let memory_offset = if flags & MAP_ANONYMOUS != 0 { 0 } else { offset };
173
174 let mut options = MappingOptions::empty();
175 if flags & MAP_SHARED != 0 {
176 options |= MappingOptions::SHARED;
177 }
178 if flags & MAP_ANONYMOUS != 0 {
179 options |= MappingOptions::ANONYMOUS;
180 }
181 #[cfg(target_arch = "x86_64")]
182 if flags & MAP_FIXED == 0 && flags & MAP_32BIT != 0 {
183 options |= MappingOptions::LOWER_32BIT;
184 }
185 if flags & MAP_GROWSDOWN != 0 {
186 options |= MappingOptions::GROWSDOWN;
187 }
188 if flags & MAP_POPULATE != 0 {
189 options |= MappingOptions::POPULATE;
190 }
191 if flags & MAP_LOCKED != 0 {
192 track_stub!(TODO("https://fxbug.dev/406377606"), "MAP_LOCKED");
195 }
196
197 security::mmap_file(current_task, file.as_ref(), prot_flags, options)?;
198
199 if flags & MAP_ANONYMOUS != 0 {
200 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "AnonymousMmap");
201 current_task.mm()?.map_anonymous(addr, length, prot_flags, options, MappingName::None)
202 } else {
203 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "FileBackedMmap");
204 let file = file.expect("file retrieved above for file-backed mapping");
206 file.mmap(current_task, addr, memory_offset, length, prot_flags, options)
207 }
208}
209
210pub fn sys_mprotect(
211 current_task: &CurrentTask,
212 addr: UserAddress,
213 length: usize,
214 prot: u32,
215) -> Result<(), Errno> {
216 let prot_flags = ProtectionFlags::from_bits(prot).ok_or_else(|| {
217 track_stub!(TODO("https://fxbug.dev/322874672"), "mprotect parse protection", prot);
218 errno!(EINVAL)
219 })?;
220 current_task.mm()?.protect(current_task, addr, length, prot_flags)?;
221 Ok(())
222}
223
224pub fn sys_mremap(
225 current_task: &CurrentTask,
226 addr: UserAddress,
227 old_length: usize,
228 new_length: usize,
229 flags: u32,
230 new_addr: UserAddress,
231) -> Result<UserAddress, Errno> {
232 let flags = MremapFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
233 let addr =
234 current_task.mm()?.remap(current_task, addr, old_length, new_length, flags, new_addr)?;
235 Ok(addr)
236}
237
238pub fn sys_munmap(
239 current_task: &CurrentTask,
240 addr: UserAddress,
241 length: usize,
242) -> Result<(), Errno> {
243 current_task.mm()?.unmap(addr, length)?;
244 Ok(())
245}
246
247pub fn sys_msync(
248 current_task: &CurrentTask,
249 addr: UserAddress,
250 length: usize,
251 flags: u32,
252) -> Result<(), Errno> {
253 let flags = MsyncFlags::from_bits_retain(flags);
254 current_task.mm()?.msync(current_task, addr, length, flags)
255}
256
257pub fn sys_madvise(
258 current_task: &CurrentTask,
259 addr: UserAddress,
260 length: usize,
261 advice: u32,
262) -> Result<(), Errno> {
263 current_task.mm()?.madvise(current_task, addr, length, advice)?;
264 Ok(())
265}
266
267pub fn sys_process_madvise(
268 _current_task: &CurrentTask,
269 _pidfd: FdNumber,
270 _iovec_addr: IOVecPtr,
271 _iovec_count: UserValue<i32>,
272 _advice: UserValue<i32>,
273 _flags: UserValue<u32>,
274) -> Result<usize, Errno> {
275 track_stub!(TODO("https://fxbug.dev/409060664"), "process_madvise");
276 error!(ENOSYS)
277}
278
279pub fn sys_brk(current_task: &CurrentTask, addr: UserAddress) -> Result<UserAddress, Errno> {
280 current_task.mm()?.set_brk(current_task, addr)
281}
282
283pub fn sys_process_vm_readv(
284 current_task: &CurrentTask,
285 tid: tid_t,
286 local_iov_addr: IOVecPtr,
287 local_iov_count: UserValue<i32>,
288 remote_iov_addr: IOVecPtr,
289 remote_iov_count: UserValue<i32>,
290 flags: usize,
291) -> Result<usize, Errno> {
292 if flags != 0 {
293 return error!(EINVAL);
294 }
295
296 if (local_iov_count == 0 && local_iov_addr.is_null())
300 || (remote_iov_count == 0 && remote_iov_addr.is_null())
301 {
302 return Ok(0);
303 }
304
305 let remote_task = current_task.get_task(tid)?;
306
307 current_task.check_ptrace_access_mode(PTRACE_MODE_ATTACH_REALCREDS, &remote_task)?;
308
309 let local_iov = current_task.read_iovec(local_iov_addr, local_iov_count)?;
310 let remote_iov = current_task.read_iovec(remote_iov_addr, remote_iov_count)?;
311 log_trace!(
312 "process_vm_readv(tid={}, local_iov={:?}, remote_iov={:?})",
313 tid,
314 local_iov,
315 remote_iov
316 );
317
318 track_stub!(TODO("https://fxbug.dev/322874765"), "process_vm_readv single-copy");
319 let mut output = UserBuffersOutputBuffer::unified_new(current_task, local_iov)?;
323 let remote_mm = remote_task.mm().ok();
324 if current_task.has_same_address_space(remote_mm.as_ref()) {
325 let mut input = UserBuffersInputBuffer::unified_new(current_task, remote_iov)?;
326 output.write_buffer(&mut input)
327 } else {
328 let mut input = UserBuffersInputBuffer::syscall_new(remote_task.deref(), remote_iov)?;
329 output.write_buffer(&mut input)
330 }
331}
332
333pub fn sys_process_vm_writev(
334 current_task: &CurrentTask,
335 tid: tid_t,
336 local_iov_addr: IOVecPtr,
337 local_iov_count: UserValue<i32>,
338 remote_iov_addr: IOVecPtr,
339 remote_iov_count: UserValue<i32>,
340 flags: usize,
341) -> Result<usize, Errno> {
342 if flags != 0 {
343 return error!(EINVAL);
344 }
345
346 if (local_iov_count == 0 && local_iov_addr.is_null())
350 || (remote_iov_count == 0 && remote_iov_addr.is_null())
351 {
352 return Ok(0);
353 }
354
355 let remote_task = current_task.get_task(tid)?;
356
357 current_task.check_ptrace_access_mode(PTRACE_MODE_ATTACH_REALCREDS, &remote_task)?;
358
359 let local_iov = current_task.read_iovec(local_iov_addr, local_iov_count)?;
360 let remote_iov = current_task.read_iovec(remote_iov_addr, remote_iov_count)?;
361 log_trace!(
362 "sys_process_vm_writev(tid={}, local_iov={:?}, remote_iov={:?})",
363 tid,
364 local_iov,
365 remote_iov
366 );
367
368 track_stub!(TODO("https://fxbug.dev/322874339"), "process_vm_writev single-copy");
369 let mut input = UserBuffersInputBuffer::unified_new(current_task, local_iov)?;
373 let remote_mm = remote_task.mm().ok();
374 if current_task.has_same_address_space(remote_mm.as_ref()) {
375 let mut output = UserBuffersOutputBuffer::unified_new(current_task, remote_iov)?;
376 output.write_buffer(&mut input)
377 } else {
378 let mut output = UserBuffersOutputBuffer::syscall_new(remote_task.deref(), remote_iov)?;
379 output.write_buffer(&mut input)
380 }
381}
382
383pub fn sys_process_mrelease(
384 current_task: &CurrentTask,
385 pidfd: FdNumber,
386 flags: u32,
387) -> Result<(), Errno> {
388 if flags != 0 {
389 return error!(EINVAL);
390 }
391 let file = current_task.files().get(pidfd)?;
392 let pidfd_file = file.downcast_file::<PidFdFileObject>().ok_or_else(|| errno!(EBADF))?;
402 let pid = pidfd_file.pid();
403 let Some(ProcessEntryRef::Process(thread_group)) = pid.get_process() else {
404 return error!(ESRCH);
405 };
406
407 let mm = {
408 let thread_group_state = thread_group.read();
409 if thread_group_state.is_running() {
414 return error!(EINVAL);
415 }
416
417 thread_group_state
422 .tasks()
423 .into_iter()
424 .find_map(|task| task.mm().ok())
425 .ok_or_else(|| errno!(ESRCH))?
426 };
427 mm.mrelease()
428}
429
430pub fn sys_membarrier(
431 current_task: &CurrentTask,
432 cmd: uapi::membarrier_cmd,
433 _flags: u32,
434 _cpu_id: i32,
435) -> Result<u32, Errno> {
436 match cmd {
437 uapi::membarrier_cmd_MEMBARRIER_CMD_QUERY => Ok(uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL
440 | uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL_EXPEDITED
441 | uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED
442 | uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED
443 | uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED
444 | uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE
445 | uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE),
446 uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL
449 | uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL_EXPEDITED => {
450 system_barrier(BarrierType::DataMemory);
451 Ok(0)
452 }
453 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED => Ok(0),
455 uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED => {
456 if current_task.mm()?.membarrier_private_expedited_registered(MembarrierType::Memory) {
459 system_barrier(BarrierType::DataMemory);
461 Ok(0)
462 } else {
463 error!(EPERM)
464 }
465 }
466 uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE => {
468 if current_task.mm()?.membarrier_private_expedited_registered(MembarrierType::SyncCore)
469 {
470 system_barrier(BarrierType::InstructionStream);
471 Ok(0)
472 } else {
473 error!(EPERM)
474 }
475 }
476 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED => {
477 let _ =
478 current_task.mm()?.register_membarrier_private_expedited(MembarrierType::Memory)?;
479 Ok(0)
480 }
481
482 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE => {
483 let _ = current_task
484 .mm()?
485 .register_membarrier_private_expedited(MembarrierType::SyncCore)?;
486 Ok(0)
487 }
488 uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ => {
489 track_stub!(TODO("https://fxbug.dev/447158570"), "membarrier rseq");
490 error!(ENOSYS)
491 }
492 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ => {
493 track_stub!(TODO("https://fxbug.dev/447158570"), "membarrier rseq");
494 error!(ENOSYS)
495 }
496 _ => error!(EINVAL),
497 }
498}
499
500pub fn sys_futex(
501 current_task: &mut CurrentTask,
502 addr: UserAddress,
503 op: u32,
504 value: u32,
505 timeout_or_value2: SyscallArg,
506 addr2: UserAddress,
507 value3: u32,
508) -> Result<usize, Errno> {
509 if op & FUTEX_PRIVATE_FLAG != 0 {
510 do_futex::<PrivateFutexKey>(current_task, addr, op, value, timeout_or_value2, addr2, value3)
511 } else {
512 do_futex::<SharedFutexKey>(current_task, addr, op, value, timeout_or_value2, addr2, value3)
513 }
514}
515
516fn do_futex<Key: FutexKey>(
517 current_task: &mut CurrentTask,
518 addr: UserAddress,
519 op: u32,
520 value: u32,
521 timeout_or_value2: SyscallArg,
522 addr2: UserAddress,
523 value3: u32,
524) -> Result<usize, Errno> {
525 let futexes = Key::get_table_from_task(current_task)?;
526 let cmd = op & (FUTEX_CMD_MASK as u32);
527
528 let is_realtime = match (cmd, op & FUTEX_CLOCK_REALTIME != 0) {
529 (FUTEX_WAIT_BITSET | FUTEX_WAIT_REQUEUE_PI | FUTEX_WAIT | FUTEX_LOCK_PI2, true) => true,
532 (_, true) => return error!(EINVAL),
533
534 (FUTEX_LOCK_PI, _) => true,
536
537 (_, false) => false,
538 };
539
540 let utime = TimeSpecPtr::new(current_task, timeout_or_value2);
543 let read_timespec = |current_task: &CurrentTask| {
544 if utime.is_null() {
545 Ok(None)
546 } else {
547 Ok(Some(current_task.read_multi_arch_object(utime)?))
548 }
549 };
550 let read_timeout = |current_task: &CurrentTask| -> Result<Option<zx::MonotonicInstant>, Errno> {
551 let Some(timespec) = read_timespec(current_task)? else {
552 return Ok(None);
553 };
554 let timeout = duration_from_timespec(timespec);
555 let deadline = zx::MonotonicInstant::after(timeout?);
556 if is_realtime {
557 track_stub!(TODO("https://fxbug.dev/356912301"), "FUTEX_CLOCK_REALTIME timeout");
560 }
561 Ok(Some(deadline))
562 };
563 let read_deadline = |current_task: &CurrentTask| -> Result<Option<TargetTime>, Errno> {
564 let Some(timespec) = read_timespec(current_task)? else {
565 return Ok(None);
566 };
567 if is_realtime {
568 Ok(Some(TargetTime::RealTime(time_from_timespec::<UtcTimeline>(timespec)?)))
569 } else {
570 Ok(Some(TargetTime::Monotonic(time_from_timespec::<zx::MonotonicTimeline>(timespec)?)))
571 }
572 };
573
574 match cmd {
575 FUTEX_WAIT => {
576 let deadline = read_timeout(current_task)?.map(TargetTime::Monotonic);
577 let bitset = FUTEX_BITSET_MATCH_ANY;
578 do_futex_wait_with_restart::<Key>(current_task, addr, value, bitset, deadline)?;
579 Ok(0)
580 }
581 FUTEX_WAKE => futexes.wake(current_task, addr, value as usize, FUTEX_BITSET_MATCH_ANY),
582 FUTEX_WAKE_OP => {
583 track_stub!(TODO("https://fxbug.dev/361181940"), "FUTEX_WAKE_OP");
584 error!(ENOSYS)
585 }
586 FUTEX_WAIT_BITSET => {
587 if value3 == 0 {
588 return error!(EINVAL);
589 }
590 let deadline = read_deadline(current_task)?;
591 do_futex_wait_with_restart::<Key>(current_task, addr, value, value3, deadline)?;
592 Ok(0)
593 }
594 FUTEX_WAKE_BITSET => {
595 if value3 == 0 {
596 return error!(EINVAL);
597 }
598 futexes.wake(current_task, addr, value as usize, value3)
599 }
600 FUTEX_REQUEUE | FUTEX_CMP_REQUEUE => {
601 let wake_count = value as usize;
602 let requeue_count: usize = timeout_or_value2.into();
603 if wake_count > i32::MAX as usize || requeue_count > i32::MAX as usize {
604 return error!(EINVAL);
605 }
606 let expected_value = if cmd == FUTEX_CMP_REQUEUE { Some(value3) } else { None };
607 futexes.requeue(current_task, addr, wake_count, requeue_count, addr2, expected_value)
608 }
609 FUTEX_WAIT_REQUEUE_PI => {
610 track_stub!(TODO("https://fxbug.dev/361181558"), "FUTEX_WAIT_REQUEUE_PI");
611 error!(ENOSYS)
612 }
613 FUTEX_CMP_REQUEUE_PI => {
614 track_stub!(TODO("https://fxbug.dev/361181773"), "FUTEX_CMP_REQUEUE_PI");
615 error!(ENOSYS)
616 }
617 FUTEX_LOCK_PI | FUTEX_LOCK_PI2 => {
618 let deadline = read_timeout(current_task)?.unwrap_or(zx::MonotonicInstant::INFINITE);
619 futexes.lock_pi(current_task, addr, deadline)?;
620 Ok(0)
621 }
622 FUTEX_TRYLOCK_PI => {
623 track_stub!(TODO("https://fxbug.dev/361175318"), "FUTEX_TRYLOCK_PI");
624 error!(ENOSYS)
625 }
626 FUTEX_UNLOCK_PI => {
627 futexes.unlock_pi(current_task, addr)?;
628 Ok(0)
629 }
630 _ => {
631 track_stub!(TODO("https://fxbug.dev/322875124"), "futex unknown command", cmd);
632 error!(ENOSYS)
633 }
634 }
635}
636
637fn do_futex_wait_with_restart<Key: FutexKey>(
638 current_task: &mut CurrentTask,
639 addr: UserAddress,
640 value: u32,
641 mask: u32,
642 deadline: Option<TargetTime>,
643) -> Result<(), Errno> {
644 let futexes = Key::get_table_from_task(current_task)?;
645 let result = match deadline {
646 None => futexes.wait(current_task, addr, value, mask, zx::MonotonicInstant::INFINITE),
647 Some(TargetTime::Monotonic(mono_deadline)) => {
648 futexes.wait(current_task, addr, value, mask, mono_deadline)
649 }
650 Some(TargetTime::BootInstant(boot_deadline)) => {
651 let timer_slack = current_task.read().get_timerslack();
652 futexes.wait_boot(current_task, addr, value, mask, boot_deadline, timer_slack)
653 }
654 Some(TargetTime::RealTime(utc_deadline)) => {
655 let (boot_deadline, _) = estimate_boot_deadline_from_utc(utc_deadline);
657 let timer_slack = current_task.read().get_timerslack();
658 futexes.wait_boot(current_task, addr, value, mask, boot_deadline, timer_slack)
659 }
660 };
661 match result {
662 Err(err) if err == EINTR => {
663 if let Some(deadline) = deadline {
664 current_task.set_syscall_restart_func(move |current_task| {
665 do_futex_wait_with_restart::<Key>(
666 current_task,
667 addr,
668 value,
669 mask,
670 Some(deadline),
671 )
672 });
673 error!(ERESTART_RESTARTBLOCK)
674 } else {
675 error!(ERESTARTSYS)
676 }
677 }
678 result => result,
679 }
680}
681
682pub fn sys_get_robust_list(
683 current_task: &CurrentTask,
684 tid: tid_t,
685 user_head_ptr: UserRef<UserAddress>,
686 user_len_ptr: UserRef<usize>,
687) -> Result<(), Errno> {
688 if tid < 0 {
689 return error!(EINVAL);
690 }
691 if user_head_ptr.is_null() || user_len_ptr.is_null() {
692 return error!(EFAULT);
693 }
694 let task = if tid == 0 {
695 current_task.task.clone()
696 } else {
697 let task = current_task.get_task(tid)?;
698 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task)?;
699 task
700 };
701 current_task.write_object(user_head_ptr, &task.read().robust_list_head.addr())?;
702 current_task.write_object(user_len_ptr, &std::mem::size_of::<robust_list_head>())?;
703 Ok(())
704}
705
706pub fn sys_set_robust_list(
707 current_task: &CurrentTask,
708 user_head: UserRef<robust_list_head>,
709 len: usize,
710) -> Result<(), Errno> {
711 if len != std::mem::size_of::<robust_list_head>() {
712 return error!(EINVAL);
713 }
714 current_task.write().robust_list_head = user_head.into();
715 Ok(())
716}
717
718pub fn sys_mlock(
719 current_task: &CurrentTask,
720 addr: UserAddress,
721 length: usize,
722) -> Result<(), Errno> {
723 sys_mlock2(current_task, addr, length, 0)
725}
726
727pub fn sys_mlock2(
728 current_task: &CurrentTask,
729 addr: UserAddress,
730 length: usize,
731 flags: u64,
732) -> Result<(), Errno> {
733 const KNOWN_FLAGS: u64 = MLOCK_ONFAULT as u64;
734 if (flags & !KNOWN_FLAGS) != 0 {
735 return error!(EINVAL);
736 }
737 let on_fault = flags & MLOCK_ONFAULT as u64 != 0;
738 current_task.mm()?.mlock(current_task, addr, length, on_fault)
739}
740
741pub fn sys_munlock(
742 current_task: &CurrentTask,
743 addr: UserAddress,
744 length: usize,
745) -> Result<(), Errno> {
746 current_task.mm()?.munlock(current_task, addr, length)
747}
748
749pub fn sys_mlockall(_current_task: &CurrentTask, _flags: u64) -> Result<(), Errno> {
750 track_stub!(TODO("https://fxbug.dev/297292097"), "mlockall()");
751 error!(ENOSYS)
752}
753
754pub fn sys_munlockall(_current_task: &CurrentTask, _flags: u64) -> Result<(), Errno> {
755 track_stub!(TODO("https://fxbug.dev/297292097"), "munlockall()");
756 error!(ENOSYS)
757}
758
759pub fn sys_mincore(
760 _current_task: &CurrentTask,
761 _addr: UserAddress,
762 _length: usize,
763 _out: UserRef<u8>,
764) -> Result<(), Errno> {
765 track_stub!(TODO("https://fxbug.dev/297372240"), "mincore()");
766 error!(ENOSYS)
767}
768
769#[cfg(target_arch = "aarch64")]
771mod arch32 {
772 use crate::mm::PAGE_SIZE;
773 use crate::mm::memory_accessor::MemoryAccessorExt;
774 use crate::mm::syscalls::{UserAddress, sys_mmap};
775 use crate::task::{CurrentTask, RobustListHeadPtr};
776 use crate::vfs::FdNumber;
777 use starnix_uapi::auth::PTRACE_MODE_READ_REALCREDS;
778 use starnix_uapi::errors::Errno;
779 use starnix_uapi::user_address::UserRef;
780 use starnix_uapi::{error, uapi};
781
782 pub fn sys_arch32_set_robust_list(
783 current_task: &CurrentTask,
784 user_head: UserRef<uapi::arch32::robust_list_head>,
785 len: usize,
786 ) -> Result<(), Errno> {
787 if len != std::mem::size_of::<uapi::arch32::robust_list_head>() {
788 return error!(EINVAL);
789 }
790 current_task.write().robust_list_head = RobustListHeadPtr::from_32(user_head);
791 Ok(())
792 }
793
794 pub fn sys_arch32_get_robust_list(
795 current_task: &CurrentTask,
796 tid: starnix_uapi::tid_t,
797 user_head_ptr: UserRef<u32>,
798 user_len_ptr: UserRef<u32>,
799 ) -> Result<(), Errno> {
800 if tid < 0 {
801 return error!(EINVAL);
802 }
803 if user_head_ptr.is_null() || user_len_ptr.is_null() {
804 return error!(EFAULT);
805 }
806 let task = if tid == 0 {
807 current_task.task.clone()
808 } else {
809 let task = current_task.get_task(tid)?;
810 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task)?;
811 task
812 };
813
814 let addr = task.read().robust_list_head.addr().ptr() as u32;
815 current_task.write_object(user_head_ptr, &addr)?;
816 current_task.write_object(
817 user_len_ptr,
818 &(std::mem::size_of::<uapi::arch32::robust_list_head>() as u32),
819 )?;
820 Ok(())
821 }
822
823 pub fn sys_arch32_mmap2(
824 current_task: &mut CurrentTask,
825 addr: UserAddress,
826 length: usize,
827 prot: u32,
828 flags: u32,
829 fd: FdNumber,
830 offset: u64,
831 ) -> Result<UserAddress, Errno> {
832 sys_mmap(current_task, addr, length, prot, flags, fd, offset * *PAGE_SIZE)
833 }
834
835 pub fn sys_arch32_munmap(
836 current_task: &CurrentTask,
837 addr: UserAddress,
838 length: usize,
839 ) -> Result<(), Errno> {
840 if !addr.is_lower_32bit() || length >= (1 << 32) {
841 return error!(EINVAL);
842 }
843 current_task.mm()?.unmap(addr, length)?;
844 Ok(())
845 }
846
847 pub use super::{
848 sys_futex as sys_arch32_futex, sys_madvise as sys_arch32_madvise,
849 sys_membarrier as sys_arch32_membarrier, sys_mincore as sys_arch32_mincore,
850 sys_mlock as sys_arch32_mlock, sys_mlock2 as sys_arch32_mlock2,
851 sys_mlockall as sys_arch32_mlockall, sys_mremap as sys_arch32_mremap,
852 sys_msync as sys_arch32_msync, sys_munlock as sys_arch32_munlock,
853 sys_munlockall as sys_arch32_munlockall,
854 sys_process_mrelease as sys_arch32_process_mrelease,
855 sys_process_vm_readv as sys_arch32_process_vm_readv,
856 };
857}
858
859#[cfg(target_arch = "aarch64")]
860pub use arch32::*;
861
862#[cfg(test)]
863mod tests {
864 use super::*;
865 use crate::mm::memory::MemoryObject;
866 use crate::testing::*;
867 use starnix_uapi::errors::EEXIST;
868 use starnix_uapi::{MREMAP_FIXED, MREMAP_MAYMOVE, PROT_READ};
869
870 #[::fuchsia::test]
871 async fn test_mmap_with_colliding_hint() {
872 spawn_kernel_and_run(async |current_task| {
873 let page_size = *PAGE_SIZE;
874
875 let mapped_address = map_memory(¤t_task, UserAddress::default(), page_size);
876 match do_mmap(
877 ¤t_task,
878 mapped_address,
879 page_size as usize,
880 PROT_READ,
881 MAP_PRIVATE | MAP_ANONYMOUS,
882 FdNumber::from_raw(-1),
883 0,
884 ) {
885 Ok(address) => {
886 assert_ne!(address, mapped_address);
887 }
888 error => {
889 panic!("mmap with colliding hint failed: {error:?}");
890 }
891 }
892 })
893 .await;
894 }
895
896 #[::fuchsia::test]
897 async fn test_mmap_with_fixed_collision() {
898 spawn_kernel_and_run(async |current_task| {
899 let page_size = *PAGE_SIZE;
900
901 let mapped_address = map_memory(¤t_task, UserAddress::default(), page_size);
902 match do_mmap(
903 ¤t_task,
904 mapped_address,
905 page_size as usize,
906 PROT_READ,
907 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
908 FdNumber::from_raw(-1),
909 0,
910 ) {
911 Ok(address) => {
912 assert_eq!(address, mapped_address);
913 }
914 error => {
915 panic!("mmap with fixed collision failed: {error:?}");
916 }
917 }
918 })
919 .await;
920 }
921
922 #[::fuchsia::test]
923 async fn test_mmap_with_fixed_noreplace_collision() {
924 spawn_kernel_and_run(async |current_task| {
925 let page_size = *PAGE_SIZE;
926
927 let mapped_address = map_memory(¤t_task, UserAddress::default(), page_size);
928 match do_mmap(
929 ¤t_task,
930 mapped_address,
931 page_size as usize,
932 PROT_READ,
933 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
934 FdNumber::from_raw(-1),
935 0,
936 ) {
937 Err(errno) => {
938 assert_eq!(errno, EEXIST);
939 }
940 result => {
941 panic!("mmap with fixed_noreplace collision failed: {result:?}");
942 }
943 }
944 })
945 .await;
946 }
947
948 #[::fuchsia::test]
951 async fn test_munmap() {
952 spawn_kernel_and_run(async |current_task| {
953 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
954 assert_eq!(sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize), Ok(()));
955
956 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
958 })
959 .await;
960 }
961
962 #[::fuchsia::test]
964 async fn test_munmap_not_mapped() {
965 spawn_kernel_and_run(async |current_task| {
966 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
967 assert_eq!(sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize), Ok(()));
968 assert_eq!(sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize), Ok(()));
969 })
970 .await;
971 }
972
973 #[::fuchsia::test]
975 async fn test_munmap_0_length() {
976 spawn_kernel_and_run(async |current_task| {
977 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
978 assert_eq!(sys_munmap(¤t_task, mapped_address, 0), error!(EINVAL));
979 })
980 .await;
981 }
982
983 #[::fuchsia::test]
985 async fn test_munmap_not_aligned() {
986 spawn_kernel_and_run(async |current_task| {
987 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
988 assert_eq!(
989 sys_munmap(¤t_task, (mapped_address + 1u64).unwrap(), *PAGE_SIZE as usize),
990 error!(EINVAL)
991 );
992
993 assert!(current_task.read_memory_to_array::<5>(mapped_address).is_ok());
995 })
996 .await;
997 }
998
999 #[::fuchsia::test]
1001 async fn test_munmap_unmap_partial() {
1002 spawn_kernel_and_run(async |current_task| {
1003 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
1004 assert_eq!(
1005 sys_munmap(¤t_task, mapped_address, (*PAGE_SIZE as usize) / 2),
1006 Ok(())
1007 );
1008
1009 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
1011 assert_eq!(
1012 current_task
1013 .read_memory_to_array::<5>((mapped_address + (*PAGE_SIZE - 2)).unwrap()),
1014 error!(EFAULT)
1015 );
1016 })
1017 .await;
1018 }
1019
1020 #[::fuchsia::test]
1022 async fn test_munmap_multiple_pages() {
1023 spawn_kernel_and_run(async |current_task| {
1024 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
1025 assert_eq!(
1026 sys_munmap(¤t_task, mapped_address, (*PAGE_SIZE as usize) + 1),
1027 Ok(())
1028 );
1029
1030 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
1032 assert_eq!(
1033 current_task
1034 .read_memory_to_array::<5>((mapped_address + (*PAGE_SIZE + 1u64)).unwrap()),
1035 error!(EFAULT)
1036 );
1037 })
1038 .await;
1039 }
1040
1041 #[::fuchsia::test]
1043 async fn test_munmap_one_of_many_pages() {
1044 spawn_kernel_and_run(async |current_task| {
1045 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
1046 assert_eq!(
1047 sys_munmap(¤t_task, mapped_address, (*PAGE_SIZE as usize) - 1),
1048 Ok(())
1049 );
1050
1051 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
1053 assert!(
1054 current_task
1055 .read_memory_to_array::<5>((mapped_address + (*PAGE_SIZE + 1u64)).unwrap())
1056 .is_ok()
1057 );
1058 })
1059 .await;
1060 }
1061
1062 #[::fuchsia::test]
1064 async fn test_munmap_middle_page() {
1065 spawn_kernel_and_run(async |current_task| {
1066 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1067 assert_eq!(
1068 sys_munmap(
1069 ¤t_task,
1070 (mapped_address + *PAGE_SIZE).unwrap(),
1071 *PAGE_SIZE as usize
1072 ),
1073 Ok(())
1074 );
1075
1076 assert!(current_task.read_memory_to_vec(mapped_address, 5).is_ok());
1078 assert_eq!(
1079 current_task.read_memory_to_vec((mapped_address + *PAGE_SIZE).unwrap(), 5),
1080 error!(EFAULT)
1081 );
1082 assert!(
1083 current_task
1084 .read_memory_to_vec((mapped_address + (*PAGE_SIZE * 2)).unwrap(), 5)
1085 .is_ok()
1086 );
1087 })
1088 .await;
1089 }
1090
1091 #[::fuchsia::test]
1093 async fn test_munmap_many_mappings() {
1094 spawn_kernel_and_run(async |current_task| {
1095 let mapped_addresses: Vec<_> = std::iter::repeat_with(|| {
1096 map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE)
1097 })
1098 .take(3)
1099 .collect();
1100 let min_address = *mapped_addresses.iter().min().unwrap();
1101 let max_address = *mapped_addresses.iter().max().unwrap();
1102 let unmap_length = (max_address - min_address) + *PAGE_SIZE as usize;
1103
1104 assert_eq!(sys_munmap(¤t_task, min_address, unmap_length), Ok(()));
1105
1106 for mapped_address in mapped_addresses {
1108 assert_eq!(current_task.read_memory_to_vec(mapped_address, 5), error!(EFAULT));
1109 }
1110 })
1111 .await;
1112 }
1113
1114 #[::fuchsia::test]
1115 async fn test_msync_validates_address_range() {
1116 spawn_kernel_and_run(async |current_task| {
1117 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1119 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 3, 0), Ok(()));
1120 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 2, 0), Ok(()));
1121 assert_eq!(
1122 sys_msync(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize * 2, 0),
1123 Ok(())
1124 );
1125
1126 sys_munmap(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize)
1128 .expect("unmap middle");
1129 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize, 0), Ok(()));
1130 assert_eq!(
1131 sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 3, starnix_uapi::MS_SYNC),
1132 error!(ENOMEM)
1133 );
1134 assert_eq!(
1135 sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 2, starnix_uapi::MS_SYNC),
1136 error!(ENOMEM)
1137 );
1138 assert_eq!(
1139 sys_msync(
1140 ¤t_task,
1141 (addr + *PAGE_SIZE).unwrap(),
1142 *PAGE_SIZE as usize * 2,
1143 starnix_uapi::MS_SYNC
1144 ),
1145 error!(ENOMEM)
1146 );
1147 assert_eq!(
1148 sys_msync(
1149 ¤t_task,
1150 (addr + (*PAGE_SIZE * 2)).unwrap(),
1151 *PAGE_SIZE as usize,
1152 0
1153 ),
1154 Ok(())
1155 );
1156
1157 assert_eq!(
1160 map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE),
1161 (addr + *PAGE_SIZE).unwrap()
1162 );
1163 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 3, 0), Ok(()));
1164 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 2, 0), Ok(()));
1165 assert_eq!(
1166 sys_msync(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize * 2, 0),
1167 Ok(())
1168 );
1169 })
1170 .await;
1171 }
1172
1173 #[::fuchsia::test]
1175 async fn test_mremap_shrink_whole_range_from_end() {
1176 spawn_kernel_and_run(async |current_task| {
1177 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
1179 fill_page(¤t_task, addr, 'a');
1180 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1181
1182 assert_eq!(
1184 remap_memory(
1185 ¤t_task,
1186 addr,
1187 *PAGE_SIZE * 2,
1188 *PAGE_SIZE,
1189 0,
1190 UserAddress::default()
1191 ),
1192 Ok(addr)
1193 );
1194
1195 check_page_eq(¤t_task, addr, 'a');
1196 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1197 })
1198 .await;
1199 }
1200
1201 #[::fuchsia::test]
1203 async fn test_mremap_shrink_partial_range() {
1204 spawn_kernel_and_run(async |current_task| {
1205 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1207 fill_page(¤t_task, addr, 'a');
1208 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1209 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1210
1211 assert_eq!(
1213 remap_memory(
1214 ¤t_task,
1215 addr,
1216 *PAGE_SIZE * 2,
1217 *PAGE_SIZE,
1218 0,
1219 UserAddress::default()
1220 ),
1221 Ok(addr)
1222 );
1223
1224 check_page_eq(¤t_task, addr, 'a');
1225 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1226 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1227 })
1228 .await;
1229 }
1230
1231 #[::fuchsia::test]
1233 async fn test_mremap_shrink_across_ranges() {
1234 spawn_kernel_and_run(async |current_task| {
1235 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1238 assert_eq!(
1239 sys_munmap(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize),
1240 Ok(())
1241 );
1242 assert_eq!(
1243 map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE),
1244 (addr + *PAGE_SIZE).unwrap()
1245 );
1246
1247 fill_page(¤t_task, addr, 'a');
1248 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1249 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1250
1251 assert_eq!(
1253 remap_memory(
1254 ¤t_task,
1255 addr,
1256 *PAGE_SIZE * 3,
1257 *PAGE_SIZE,
1258 0,
1259 UserAddress::default()
1260 ),
1261 Ok(addr)
1262 );
1263
1264 check_page_eq(¤t_task, addr, 'a');
1265 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1266 check_unmapped(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap());
1267 })
1268 .await;
1269 }
1270
1271 #[::fuchsia::test]
1273 async fn test_mremap_grow_in_place() {
1274 spawn_kernel_and_run(async |current_task| {
1275 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1277 fill_page(¤t_task, addr, 'a');
1278 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1279 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1280 assert_eq!(
1281 sys_munmap(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize),
1282 Ok(())
1283 );
1284
1285 assert_eq!(
1287 remap_memory(
1288 ¤t_task,
1289 addr,
1290 *PAGE_SIZE,
1291 *PAGE_SIZE * 2,
1292 0,
1293 UserAddress::default()
1294 ),
1295 Ok(addr)
1296 );
1297
1298 check_page_eq(¤t_task, addr, 'a');
1299
1300 check_page_ne(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1303
1304 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1305 })
1306 .await;
1307 }
1308
1309 #[::fuchsia::test]
1311 async fn test_mremap_grow_maymove() {
1312 spawn_kernel_and_run(async |current_task| {
1313 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1315 fill_page(¤t_task, addr, 'a');
1316 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1317 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1318
1319 let new_addr = remap_memory(
1321 ¤t_task,
1322 addr,
1323 *PAGE_SIZE * 2,
1324 *PAGE_SIZE * 3,
1325 MREMAP_MAYMOVE,
1326 UserAddress::default(),
1327 )
1328 .expect("failed to mremap");
1329
1330 assert_ne!(new_addr, addr, "mremap did not move the mapping");
1331
1332 check_unmapped(¤t_task, addr);
1334 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1335
1336 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1338
1339 check_page_eq(¤t_task, new_addr, 'a');
1341 check_page_eq(¤t_task, (new_addr + *PAGE_SIZE).unwrap(), 'b');
1342
1343 check_page_ne(¤t_task, (new_addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1345 })
1346 .await;
1347 }
1348
1349 #[::fuchsia::test]
1351 async fn test_mremap_shrink_fixed() {
1352 spawn_kernel_and_run(async |current_task| {
1353 let dst_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
1355 fill_page(¤t_task, dst_addr, 'y');
1356 fill_page(¤t_task, (dst_addr + *PAGE_SIZE).unwrap(), 'z');
1357
1358 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1360 fill_page(¤t_task, addr, 'a');
1361 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1362 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1363
1364 let new_addr = remap_memory(
1366 ¤t_task,
1367 addr,
1368 *PAGE_SIZE * 2,
1369 *PAGE_SIZE,
1370 MREMAP_MAYMOVE | MREMAP_FIXED,
1371 dst_addr,
1372 )
1373 .expect("failed to mremap");
1374
1375 assert_eq!(new_addr, dst_addr, "mremap did not move the mapping");
1376
1377 check_unmapped(¤t_task, addr);
1379 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1380
1381 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1383
1384 check_page_eq(¤t_task, new_addr, 'a');
1386
1387 check_page_eq(¤t_task, (new_addr + *PAGE_SIZE).unwrap(), 'z');
1389 })
1390 .await;
1391 }
1392
1393 #[::fuchsia::test]
1395 async fn test_mremap_clobber_memory_mapping() {
1396 spawn_kernel_and_run(async |current_task| {
1397 let dst_memory = MemoryObject::from(zx::Vmo::create(2 * *PAGE_SIZE).unwrap());
1398 dst_memory.write(&['x' as u8].repeat(*PAGE_SIZE as usize), 0).unwrap();
1399 dst_memory.write(&['y' as u8].repeat(*PAGE_SIZE as usize), *PAGE_SIZE).unwrap();
1400
1401 let dst_addr = current_task
1402 .mm()
1403 .unwrap()
1404 .map_memory(
1405 DesiredAddress::Any,
1406 dst_memory.into(),
1407 0,
1408 2 * (*PAGE_SIZE as usize),
1409 ProtectionFlags::READ,
1410 MappingOptions::empty(),
1411 MappingName::None,
1412 )
1413 .unwrap();
1414
1415 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1417 fill_page(¤t_task, addr, 'a');
1418 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1419 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1420
1421 let remapped_addr = sys_mremap(
1423 &*current_task,
1424 (addr + *PAGE_SIZE).unwrap(),
1425 *PAGE_SIZE as usize,
1426 *PAGE_SIZE as usize,
1427 MREMAP_FIXED | MREMAP_MAYMOVE,
1428 (dst_addr + *PAGE_SIZE).unwrap(),
1429 )
1430 .unwrap();
1431
1432 assert_eq!(remapped_addr, (dst_addr + *PAGE_SIZE).unwrap());
1433
1434 check_page_eq(¤t_task, addr, 'a');
1435 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1436 check_page_eq(¤t_task, (addr + (2 * *PAGE_SIZE)).unwrap(), 'c');
1437
1438 check_page_eq(¤t_task, dst_addr, 'x');
1439 check_page_eq(¤t_task, (dst_addr + *PAGE_SIZE).unwrap(), 'b');
1440 })
1441 .await;
1442 }
1443
1444 #[cfg(target_arch = "x86_64")]
1445 #[::fuchsia::test]
1446 async fn test_map_32_bit() {
1447 use starnix_uapi::PROT_WRITE;
1448
1449 spawn_kernel_and_run(async |current_task| {
1450 let page_size = *PAGE_SIZE;
1451
1452 for _i in 0..256 {
1453 match do_mmap(
1454 ¤t_task,
1455 UserAddress::from(0),
1456 page_size as usize,
1457 PROT_READ | PROT_WRITE,
1458 MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT,
1459 FdNumber::from_raw(-1),
1460 0,
1461 ) {
1462 Ok(address) => {
1463 let memory_end = address.ptr() + page_size as usize;
1464 assert!(memory_end <= 0x80000000);
1465 }
1466 error => {
1467 panic!("mmap with MAP_32BIT failed: {error:?}");
1468 }
1469 }
1470 }
1471 })
1472 .await;
1473 }
1474}