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