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, timespec_from_time};
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(
179 current_task,
180 addr,
181 memory_offset,
182 length,
183 prot_flags,
184 options,
185 file.name.to_passive(),
186 )
187 }
188}
189
190pub fn sys_mprotect(
191 current_task: &CurrentTask,
192 addr: UserAddress,
193 length: usize,
194 prot: u32,
195) -> Result<(), Errno> {
196 let prot_flags = ProtectionFlags::from_bits(prot).ok_or_else(|| {
197 track_stub!(TODO("https://fxbug.dev/322874672"), "mprotect parse protection", prot);
198 errno!(EINVAL)
199 })?;
200 current_task.mm()?.protect(current_task, addr, length, prot_flags)?;
201 Ok(())
202}
203
204pub fn sys_mremap(
205 current_task: &CurrentTask,
206 addr: UserAddress,
207 old_length: usize,
208 new_length: usize,
209 flags: u32,
210 new_addr: UserAddress,
211) -> Result<UserAddress, Errno> {
212 let flags = MremapFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
213 let addr =
214 current_task.mm()?.remap(current_task, addr, old_length, new_length, flags, new_addr)?;
215 Ok(addr)
216}
217
218pub fn sys_munmap(
219 current_task: &CurrentTask,
220 addr: UserAddress,
221 length: usize,
222) -> Result<(), Errno> {
223 current_task.mm()?.unmap(addr, length)?;
224 Ok(())
225}
226
227pub fn sys_msync(
228 current_task: &CurrentTask,
229 addr: UserAddress,
230 length: usize,
231 flags: u32,
232) -> Result<(), Errno> {
233 let flags = MsyncFlags::from_bits_retain(flags);
234 current_task.mm()?.msync(current_task, addr, length, flags)
235}
236
237pub fn sys_madvise(
238 current_task: &CurrentTask,
239 addr: UserAddress,
240 length: usize,
241 advice: u32,
242) -> Result<(), Errno> {
243 current_task.mm()?.madvise(addr, length, advice)?;
244 Ok(())
245}
246
247pub fn sys_process_madvise(
248 _current_task: &CurrentTask,
249 _pidfd: FdNumber,
250 _iovec_addr: IOVecPtr,
251 _iovec_count: UserValue<i32>,
252 _advice: UserValue<i32>,
253 _flags: UserValue<u32>,
254) -> Result<usize, Errno> {
255 track_stub!(TODO("https://fxbug.dev/409060664"), "process_madvise");
256 error!(ENOSYS)
257}
258
259pub fn sys_brk(current_task: &CurrentTask, addr: UserAddress) -> Result<UserAddress, Errno> {
260 current_task.mm()?.set_brk(current_task, addr)
261}
262
263pub fn sys_process_vm_readv(
264 current_task: &CurrentTask,
265 tid: tid_t,
266 local_iov_addr: IOVecPtr,
267 local_iov_count: UserValue<i32>,
268 remote_iov_addr: IOVecPtr,
269 remote_iov_count: UserValue<i32>,
270 flags: usize,
271) -> Result<usize, Errno> {
272 if flags != 0 {
273 return error!(EINVAL);
274 }
275
276 if (local_iov_count == 0 && local_iov_addr.is_null())
280 || (remote_iov_count == 0 && remote_iov_addr.is_null())
281 {
282 return Ok(0);
283 }
284
285 let remote_task = current_task.get_task(tid)?;
286
287 current_task.check_ptrace_access_mode(PTRACE_MODE_ATTACH_REALCREDS, &remote_task)?;
288
289 let local_iov = current_task.read_iovec(local_iov_addr, local_iov_count)?;
290 let remote_iov = current_task.read_iovec(remote_iov_addr, remote_iov_count)?;
291 log_trace!(
292 "process_vm_readv(tid={}, local_iov={:?}, remote_iov={:?})",
293 tid,
294 local_iov,
295 remote_iov
296 );
297
298 track_stub!(TODO("https://fxbug.dev/322874765"), "process_vm_readv single-copy");
299 let mut output = UserBuffersOutputBuffer::unified_new(current_task, local_iov)?;
303 let remote_mm = remote_task.mm().ok();
304 if current_task.has_same_address_space(remote_mm.as_ref()) {
305 let mut input = UserBuffersInputBuffer::unified_new(current_task, remote_iov)?;
306 output.write_buffer(&mut input)
307 } else {
308 let mut input = UserBuffersInputBuffer::syscall_new(remote_task.deref(), remote_iov)?;
309 output.write_buffer(&mut input)
310 }
311}
312
313pub fn sys_process_vm_writev(
314 current_task: &CurrentTask,
315 tid: tid_t,
316 local_iov_addr: IOVecPtr,
317 local_iov_count: UserValue<i32>,
318 remote_iov_addr: IOVecPtr,
319 remote_iov_count: UserValue<i32>,
320 flags: usize,
321) -> Result<usize, Errno> {
322 if flags != 0 {
323 return error!(EINVAL);
324 }
325
326 if (local_iov_count == 0 && local_iov_addr.is_null())
330 || (remote_iov_count == 0 && remote_iov_addr.is_null())
331 {
332 return Ok(0);
333 }
334
335 let remote_task = current_task.get_task(tid)?;
336
337 current_task.check_ptrace_access_mode(PTRACE_MODE_ATTACH_REALCREDS, &remote_task)?;
338
339 let local_iov = current_task.read_iovec(local_iov_addr, local_iov_count)?;
340 let remote_iov = current_task.read_iovec(remote_iov_addr, remote_iov_count)?;
341 log_trace!(
342 "sys_process_vm_writev(tid={}, local_iov={:?}, remote_iov={:?})",
343 tid,
344 local_iov,
345 remote_iov
346 );
347
348 track_stub!(TODO("https://fxbug.dev/322874339"), "process_vm_writev single-copy");
349 let mut input = UserBuffersInputBuffer::unified_new(current_task, local_iov)?;
353 let remote_mm = remote_task.mm().ok();
354 if current_task.has_same_address_space(remote_mm.as_ref()) {
355 let mut output = UserBuffersOutputBuffer::unified_new(current_task, remote_iov)?;
356 output.write_buffer(&mut input)
357 } else {
358 let mut output = UserBuffersOutputBuffer::syscall_new(remote_task.deref(), remote_iov)?;
359 output.write_buffer(&mut input)
360 }
361}
362
363pub fn sys_process_mrelease(
364 current_task: &CurrentTask,
365 pidfd: FdNumber,
366 flags: u32,
367) -> Result<(), Errno> {
368 if flags != 0 {
369 return error!(EINVAL);
370 }
371 let file = current_task.files().get(pidfd)?;
372 let task = current_task.get_task(file.as_thread_group_key()?.pid())?;
373 if !task.load_stopped().is_stopped() {
374 return error!(EINVAL);
375 }
376
377 task.mm()?.mrelease()
378}
379
380pub fn sys_membarrier(
381 current_task: &CurrentTask,
382 cmd: uapi::membarrier_cmd,
383 _flags: u32,
384 _cpu_id: i32,
385) -> Result<u32, Errno> {
386 match cmd {
387 uapi::membarrier_cmd_MEMBARRIER_CMD_QUERY => Ok(uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL
390 | uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL_EXPEDITED
391 | uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED
392 | uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED
393 | uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED
394 | uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE
395 | uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE),
396 uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL
399 | uapi::membarrier_cmd_MEMBARRIER_CMD_GLOBAL_EXPEDITED => {
400 system_barrier(BarrierType::DataMemory);
401 Ok(0)
402 }
403 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED => Ok(0),
405 uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED => {
406 if current_task.mm()?.membarrier_private_expedited_registered(MembarrierType::Memory) {
409 system_barrier(BarrierType::DataMemory);
411 Ok(0)
412 } else {
413 error!(EPERM)
414 }
415 }
416 uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE => {
418 if current_task.mm()?.membarrier_private_expedited_registered(MembarrierType::SyncCore)
419 {
420 system_barrier(BarrierType::InstructionStream);
421 Ok(0)
422 } else {
423 error!(EPERM)
424 }
425 }
426 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED => {
427 let _ =
428 current_task.mm()?.register_membarrier_private_expedited(MembarrierType::Memory)?;
429 Ok(0)
430 }
431
432 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE => {
433 let _ = current_task
434 .mm()?
435 .register_membarrier_private_expedited(MembarrierType::SyncCore)?;
436 Ok(0)
437 }
438 uapi::membarrier_cmd_MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ => {
439 track_stub!(TODO("https://fxbug.dev/447158570"), "membarrier rseq");
440 error!(ENOSYS)
441 }
442 uapi::membarrier_cmd_MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ => {
443 track_stub!(TODO("https://fxbug.dev/447158570"), "membarrier rseq");
444 error!(ENOSYS)
445 }
446 _ => error!(EINVAL),
447 }
448}
449
450pub fn sys_futex(
451 current_task: &mut CurrentTask,
452 addr: UserAddress,
453 op: u32,
454 value: u32,
455 timeout_or_value2: SyscallArg,
456 addr2: UserAddress,
457 value3: u32,
458) -> Result<usize, Errno> {
459 if op & FUTEX_PRIVATE_FLAG != 0 {
460 do_futex::<PrivateFutexKey>(current_task, addr, op, value, timeout_or_value2, addr2, value3)
461 } else {
462 do_futex::<SharedFutexKey>(current_task, addr, op, value, timeout_or_value2, addr2, value3)
463 }
464}
465
466fn do_futex<Key: FutexKey>(
467 current_task: &mut CurrentTask,
468 addr: UserAddress,
469 op: u32,
470 value: u32,
471 timeout_or_value2: SyscallArg,
472 addr2: UserAddress,
473 value3: u32,
474) -> Result<usize, Errno> {
475 let futexes = Key::get_table_from_task(current_task)?;
476 let cmd = op & (FUTEX_CMD_MASK as u32);
477
478 let is_realtime = match (cmd, op & FUTEX_CLOCK_REALTIME != 0) {
479 (FUTEX_WAIT_BITSET | FUTEX_WAIT_REQUEUE_PI | FUTEX_WAIT | FUTEX_LOCK_PI2, true) => true,
482 (_, true) => return error!(EINVAL),
483
484 (FUTEX_LOCK_PI, _) => true,
486
487 (_, false) => false,
488 };
489
490 let read_timespec = |current_task: &CurrentTask| {
493 let utime = TimeSpecPtr::new(current_task, timeout_or_value2);
494 if utime.is_null() {
495 Ok(timespec_from_time(zx::MonotonicInstant::INFINITE))
496 } else {
497 current_task.read_multi_arch_object(utime)
498 }
499 };
500 let read_timeout = |current_task: &CurrentTask| {
501 let timespec = read_timespec(current_task)?;
502 let timeout = duration_from_timespec(timespec);
503 let deadline = zx::MonotonicInstant::after(timeout?);
504 if is_realtime {
505 track_stub!(TODO("https://fxbug.dev/356912301"), "FUTEX_CLOCK_REALTIME timeout");
508 }
509 Ok(deadline)
510 };
511 let read_deadline = |current_task: &CurrentTask| {
512 let timespec = read_timespec(current_task)?;
513 if is_realtime {
514 Ok(TargetTime::RealTime(time_from_timespec::<UtcTimeline>(timespec)?))
515 } else {
516 Ok(TargetTime::Monotonic(time_from_timespec::<zx::MonotonicTimeline>(timespec)?))
517 }
518 };
519
520 match cmd {
521 FUTEX_WAIT => {
522 let deadline = read_timeout(current_task)?;
523 let bitset = FUTEX_BITSET_MATCH_ANY;
524 do_futex_wait_with_restart::<Key>(
525 current_task,
526 addr,
527 value,
528 bitset,
529 TargetTime::Monotonic(deadline),
530 )?;
531 Ok(0)
532 }
533 FUTEX_WAKE => futexes.wake(current_task, addr, value as usize, FUTEX_BITSET_MATCH_ANY),
534 FUTEX_WAKE_OP => {
535 track_stub!(TODO("https://fxbug.dev/361181940"), "FUTEX_WAKE_OP");
536 error!(ENOSYS)
537 }
538 FUTEX_WAIT_BITSET => {
539 if value3 == 0 {
540 return error!(EINVAL);
541 }
542 let deadline = read_deadline(current_task)?;
543 do_futex_wait_with_restart::<Key>(current_task, addr, value, value3, deadline)?;
544 Ok(0)
545 }
546 FUTEX_WAKE_BITSET => {
547 if value3 == 0 {
548 return error!(EINVAL);
549 }
550 futexes.wake(current_task, addr, value as usize, value3)
551 }
552 FUTEX_REQUEUE | FUTEX_CMP_REQUEUE => {
553 let wake_count = value as usize;
554 let requeue_count: usize = timeout_or_value2.into();
555 if wake_count > std::i32::MAX as usize || requeue_count > std::i32::MAX as usize {
556 return error!(EINVAL);
557 }
558 let expected_value = if cmd == FUTEX_CMP_REQUEUE { Some(value3) } else { None };
559 futexes.requeue(current_task, addr, wake_count, requeue_count, addr2, expected_value)
560 }
561 FUTEX_WAIT_REQUEUE_PI => {
562 track_stub!(TODO("https://fxbug.dev/361181558"), "FUTEX_WAIT_REQUEUE_PI");
563 error!(ENOSYS)
564 }
565 FUTEX_CMP_REQUEUE_PI => {
566 track_stub!(TODO("https://fxbug.dev/361181773"), "FUTEX_CMP_REQUEUE_PI");
567 error!(ENOSYS)
568 }
569 FUTEX_LOCK_PI | FUTEX_LOCK_PI2 => {
570 futexes.lock_pi(current_task, addr, read_timeout(current_task)?)?;
571 Ok(0)
572 }
573 FUTEX_TRYLOCK_PI => {
574 track_stub!(TODO("https://fxbug.dev/361175318"), "FUTEX_TRYLOCK_PI");
575 error!(ENOSYS)
576 }
577 FUTEX_UNLOCK_PI => {
578 futexes.unlock_pi(current_task, addr)?;
579 Ok(0)
580 }
581 _ => {
582 track_stub!(TODO("https://fxbug.dev/322875124"), "futex unknown command", cmd);
583 error!(ENOSYS)
584 }
585 }
586}
587
588fn do_futex_wait_with_restart<Key: FutexKey>(
589 current_task: &mut CurrentTask,
590 addr: UserAddress,
591 value: u32,
592 mask: u32,
593 deadline: TargetTime,
594) -> Result<(), Errno> {
595 let futexes = Key::get_table_from_task(current_task)?;
596 let result = match deadline {
597 TargetTime::Monotonic(mono_deadline) => {
598 futexes.wait(current_task, addr, value, mask, mono_deadline)
599 }
600 TargetTime::BootInstant(boot_deadline) => {
601 let timer_slack = current_task.read().get_timerslack();
602 futexes.wait_boot(current_task, addr, value, mask, boot_deadline, timer_slack)
603 }
604 TargetTime::RealTime(utc_deadline) => {
605 let (boot_deadline, _) = estimate_boot_deadline_from_utc(utc_deadline);
607 let timer_slack = current_task.read().get_timerslack();
608 futexes.wait_boot(current_task, addr, value, mask, boot_deadline, timer_slack)
609 }
610 };
611 match result {
612 Err(err) if err == EINTR => {
613 current_task.set_syscall_restart_func(move |current_task| {
614 do_futex_wait_with_restart::<Key>(current_task, addr, value, mask, deadline)
615 });
616 error!(ERESTART_RESTARTBLOCK)
617 }
618 result => result,
619 }
620}
621
622pub fn sys_get_robust_list(
623 current_task: &CurrentTask,
624 tid: tid_t,
625 user_head_ptr: UserRef<UserAddress>,
626 user_len_ptr: UserRef<usize>,
627) -> Result<(), Errno> {
628 if tid < 0 {
629 return error!(EINVAL);
630 }
631 if user_head_ptr.is_null() || user_len_ptr.is_null() {
632 return error!(EFAULT);
633 }
634 let task = if tid == 0 {
635 current_task.task.clone()
636 } else {
637 let task = current_task.get_task(tid)?;
638 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task)?;
639 task
640 };
641 current_task.write_object(user_head_ptr, &task.read().robust_list_head.addr())?;
642 current_task.write_object(user_len_ptr, &std::mem::size_of::<robust_list_head>())?;
643 Ok(())
644}
645
646pub fn sys_set_robust_list(
647 current_task: &CurrentTask,
648 user_head: UserRef<robust_list_head>,
649 len: usize,
650) -> Result<(), Errno> {
651 if len != std::mem::size_of::<robust_list_head>() {
652 return error!(EINVAL);
653 }
654 current_task.write().robust_list_head = user_head.into();
655 Ok(())
656}
657
658pub fn sys_mlock(
659 current_task: &CurrentTask,
660 addr: UserAddress,
661 length: usize,
662) -> Result<(), Errno> {
663 sys_mlock2(current_task, addr, length, 0)
665}
666
667pub fn sys_mlock2(
668 current_task: &CurrentTask,
669 addr: UserAddress,
670 length: usize,
671 flags: u64,
672) -> Result<(), Errno> {
673 const KNOWN_FLAGS: u64 = MLOCK_ONFAULT as u64;
674 if (flags & !KNOWN_FLAGS) != 0 {
675 return error!(EINVAL);
676 }
677 let on_fault = flags & MLOCK_ONFAULT as u64 != 0;
678 current_task.mm()?.mlock(current_task, addr, length, on_fault)
679}
680
681pub fn sys_munlock(
682 current_task: &CurrentTask,
683 addr: UserAddress,
684 length: usize,
685) -> Result<(), Errno> {
686 current_task.mm()?.munlock(current_task, addr, length)
687}
688
689pub fn sys_mlockall(_current_task: &CurrentTask, _flags: u64) -> Result<(), Errno> {
690 track_stub!(TODO("https://fxbug.dev/297292097"), "mlockall()");
691 error!(ENOSYS)
692}
693
694pub fn sys_munlockall(_current_task: &CurrentTask, _flags: u64) -> Result<(), Errno> {
695 track_stub!(TODO("https://fxbug.dev/297292097"), "munlockall()");
696 error!(ENOSYS)
697}
698
699pub fn sys_mincore(
700 _current_task: &CurrentTask,
701 _addr: UserAddress,
702 _length: usize,
703 _out: UserRef<u8>,
704) -> Result<(), Errno> {
705 track_stub!(TODO("https://fxbug.dev/297372240"), "mincore()");
706 error!(ENOSYS)
707}
708
709#[cfg(target_arch = "aarch64")]
711mod arch32 {
712 use crate::mm::PAGE_SIZE;
713 use crate::mm::memory_accessor::MemoryAccessorExt;
714 use crate::mm::syscalls::{UserAddress, sys_mmap};
715 use crate::task::{CurrentTask, RobustListHeadPtr};
716 use crate::vfs::FdNumber;
717 use starnix_uapi::auth::PTRACE_MODE_READ_REALCREDS;
718 use starnix_uapi::errors::Errno;
719 use starnix_uapi::user_address::UserRef;
720 use starnix_uapi::{error, uapi};
721
722 pub fn sys_arch32_set_robust_list(
723 current_task: &CurrentTask,
724 user_head: UserRef<uapi::arch32::robust_list_head>,
725 len: usize,
726 ) -> Result<(), Errno> {
727 if len != std::mem::size_of::<uapi::arch32::robust_list_head>() {
728 return error!(EINVAL);
729 }
730 current_task.write().robust_list_head = RobustListHeadPtr::from_32(user_head);
731 Ok(())
732 }
733
734 pub fn sys_arch32_get_robust_list(
735 current_task: &CurrentTask,
736 tid: starnix_uapi::tid_t,
737 user_head_ptr: UserRef<u32>,
738 user_len_ptr: UserRef<u32>,
739 ) -> Result<(), Errno> {
740 if tid < 0 {
741 return error!(EINVAL);
742 }
743 if user_head_ptr.is_null() || user_len_ptr.is_null() {
744 return error!(EFAULT);
745 }
746 let task = if tid == 0 {
747 current_task.task.clone()
748 } else {
749 let task = current_task.get_task(tid)?;
750 current_task.check_ptrace_access_mode(PTRACE_MODE_READ_REALCREDS, &task)?;
751 task
752 };
753
754 let addr = task.read().robust_list_head.addr().ptr() as u32;
755 current_task.write_object(user_head_ptr, &addr)?;
756 current_task.write_object(
757 user_len_ptr,
758 &(std::mem::size_of::<uapi::arch32::robust_list_head>() as u32),
759 )?;
760 Ok(())
761 }
762
763 pub fn sys_arch32_mmap2(
764 current_task: &mut CurrentTask,
765 addr: UserAddress,
766 length: usize,
767 prot: u32,
768 flags: u32,
769 fd: FdNumber,
770 offset: u64,
771 ) -> Result<UserAddress, Errno> {
772 sys_mmap(current_task, addr, length, prot, flags, fd, offset * *PAGE_SIZE)
773 }
774
775 pub fn sys_arch32_munmap(
776 current_task: &CurrentTask,
777 addr: UserAddress,
778 length: usize,
779 ) -> Result<(), Errno> {
780 if !addr.is_lower_32bit() || length >= (1 << 32) {
781 return error!(EINVAL);
782 }
783 current_task.mm()?.unmap(addr, length)?;
784 Ok(())
785 }
786
787 pub use super::{
788 sys_futex as sys_arch32_futex, sys_madvise as sys_arch32_madvise,
789 sys_membarrier as sys_arch32_membarrier, sys_mincore as sys_arch32_mincore,
790 sys_mlock as sys_arch32_mlock, sys_mlock2 as sys_arch32_mlock2,
791 sys_mlockall as sys_arch32_mlockall, sys_mremap as sys_arch32_mremap,
792 sys_msync as sys_arch32_msync, sys_munlock as sys_arch32_munlock,
793 sys_munlockall as sys_arch32_munlockall,
794 sys_process_mrelease as sys_arch32_process_mrelease,
795 sys_process_vm_readv as sys_arch32_process_vm_readv,
796 };
797}
798
799#[cfg(target_arch = "aarch64")]
800pub use arch32::*;
801
802#[cfg(test)]
803mod tests {
804 use super::*;
805 use crate::mm::memory::MemoryObject;
806 use crate::testing::*;
807 use starnix_uapi::errors::EEXIST;
808 use starnix_uapi::file_mode::Access;
809 use starnix_uapi::{MREMAP_FIXED, MREMAP_MAYMOVE, PROT_READ};
810
811 #[::fuchsia::test]
812 async fn test_mmap_with_colliding_hint() {
813 spawn_kernel_and_run(async |current_task| {
814 let page_size = *PAGE_SIZE;
815
816 let mapped_address = map_memory(¤t_task, UserAddress::default(), page_size);
817 match do_mmap(
818 ¤t_task,
819 mapped_address,
820 page_size as usize,
821 PROT_READ,
822 MAP_PRIVATE | MAP_ANONYMOUS,
823 FdNumber::from_raw(-1),
824 0,
825 ) {
826 Ok(address) => {
827 assert_ne!(address, mapped_address);
828 }
829 error => {
830 panic!("mmap with colliding hint failed: {error:?}");
831 }
832 }
833 })
834 .await;
835 }
836
837 #[::fuchsia::test]
838 async fn test_mmap_with_fixed_collision() {
839 spawn_kernel_and_run(async |current_task| {
840 let page_size = *PAGE_SIZE;
841
842 let mapped_address = map_memory(¤t_task, UserAddress::default(), page_size);
843 match do_mmap(
844 ¤t_task,
845 mapped_address,
846 page_size as usize,
847 PROT_READ,
848 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
849 FdNumber::from_raw(-1),
850 0,
851 ) {
852 Ok(address) => {
853 assert_eq!(address, mapped_address);
854 }
855 error => {
856 panic!("mmap with fixed collision failed: {error:?}");
857 }
858 }
859 })
860 .await;
861 }
862
863 #[::fuchsia::test]
864 async fn test_mmap_with_fixed_noreplace_collision() {
865 spawn_kernel_and_run(async |current_task| {
866 let page_size = *PAGE_SIZE;
867
868 let mapped_address = map_memory(¤t_task, UserAddress::default(), page_size);
869 match do_mmap(
870 ¤t_task,
871 mapped_address,
872 page_size as usize,
873 PROT_READ,
874 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
875 FdNumber::from_raw(-1),
876 0,
877 ) {
878 Err(errno) => {
879 assert_eq!(errno, EEXIST);
880 }
881 result => {
882 panic!("mmap with fixed_noreplace collision failed: {result:?}");
883 }
884 }
885 })
886 .await;
887 }
888
889 #[::fuchsia::test]
892 async fn test_munmap() {
893 spawn_kernel_and_run(async |current_task| {
894 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
895 assert_eq!(sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize), Ok(()));
896
897 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
899 })
900 .await;
901 }
902
903 #[::fuchsia::test]
905 async fn test_munmap_not_mapped() {
906 spawn_kernel_and_run(async |current_task| {
907 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
908 assert_eq!(sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize), Ok(()));
909 assert_eq!(sys_munmap(¤t_task, mapped_address, *PAGE_SIZE as usize), Ok(()));
910 })
911 .await;
912 }
913
914 #[::fuchsia::test]
916 async fn test_munmap_0_length() {
917 spawn_kernel_and_run(async |current_task| {
918 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
919 assert_eq!(sys_munmap(¤t_task, mapped_address, 0), error!(EINVAL));
920 })
921 .await;
922 }
923
924 #[::fuchsia::test]
926 async fn test_munmap_not_aligned() {
927 spawn_kernel_and_run(async |current_task| {
928 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
929 assert_eq!(
930 sys_munmap(¤t_task, (mapped_address + 1u64).unwrap(), *PAGE_SIZE as usize),
931 error!(EINVAL)
932 );
933
934 assert!(current_task.read_memory_to_array::<5>(mapped_address).is_ok());
936 })
937 .await;
938 }
939
940 #[::fuchsia::test]
942 async fn test_munmap_unmap_partial() {
943 spawn_kernel_and_run(async |current_task| {
944 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
945 assert_eq!(
946 sys_munmap(¤t_task, mapped_address, (*PAGE_SIZE as usize) / 2),
947 Ok(())
948 );
949
950 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
952 assert_eq!(
953 current_task
954 .read_memory_to_array::<5>((mapped_address + (*PAGE_SIZE - 2)).unwrap()),
955 error!(EFAULT)
956 );
957 })
958 .await;
959 }
960
961 #[::fuchsia::test]
963 async fn test_munmap_multiple_pages() {
964 spawn_kernel_and_run(async |current_task| {
965 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
966 assert_eq!(
967 sys_munmap(¤t_task, mapped_address, (*PAGE_SIZE as usize) + 1),
968 Ok(())
969 );
970
971 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
973 assert_eq!(
974 current_task
975 .read_memory_to_array::<5>((mapped_address + (*PAGE_SIZE + 1u64)).unwrap()),
976 error!(EFAULT)
977 );
978 })
979 .await;
980 }
981
982 #[::fuchsia::test]
984 async fn test_munmap_one_of_many_pages() {
985 spawn_kernel_and_run(async |current_task| {
986 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
987 assert_eq!(
988 sys_munmap(¤t_task, mapped_address, (*PAGE_SIZE as usize) - 1),
989 Ok(())
990 );
991
992 assert_eq!(current_task.read_memory_to_array::<5>(mapped_address), error!(EFAULT));
994 assert!(
995 current_task
996 .read_memory_to_array::<5>((mapped_address + (*PAGE_SIZE + 1u64)).unwrap())
997 .is_ok()
998 );
999 })
1000 .await;
1001 }
1002
1003 #[::fuchsia::test]
1005 async fn test_munmap_middle_page() {
1006 spawn_kernel_and_run(async |current_task| {
1007 let mapped_address = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1008 assert_eq!(
1009 sys_munmap(
1010 ¤t_task,
1011 (mapped_address + *PAGE_SIZE).unwrap(),
1012 *PAGE_SIZE as usize
1013 ),
1014 Ok(())
1015 );
1016
1017 assert!(current_task.read_memory_to_vec(mapped_address, 5).is_ok());
1019 assert_eq!(
1020 current_task.read_memory_to_vec((mapped_address + *PAGE_SIZE).unwrap(), 5),
1021 error!(EFAULT)
1022 );
1023 assert!(
1024 current_task
1025 .read_memory_to_vec((mapped_address + (*PAGE_SIZE * 2)).unwrap(), 5)
1026 .is_ok()
1027 );
1028 })
1029 .await;
1030 }
1031
1032 #[::fuchsia::test]
1034 async fn test_munmap_many_mappings() {
1035 spawn_kernel_and_run(async |current_task| {
1036 let mapped_addresses: Vec<_> = std::iter::repeat_with(|| {
1037 map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE)
1038 })
1039 .take(3)
1040 .collect();
1041 let min_address = *mapped_addresses.iter().min().unwrap();
1042 let max_address = *mapped_addresses.iter().max().unwrap();
1043 let unmap_length = (max_address - min_address) + *PAGE_SIZE as usize;
1044
1045 assert_eq!(sys_munmap(¤t_task, min_address, unmap_length), Ok(()));
1046
1047 for mapped_address in mapped_addresses {
1049 assert_eq!(current_task.read_memory_to_vec(mapped_address, 5), error!(EFAULT));
1050 }
1051 })
1052 .await;
1053 }
1054
1055 #[::fuchsia::test]
1056 async fn test_msync_validates_address_range() {
1057 spawn_kernel_and_run(async |current_task| {
1058 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1060 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 3, 0), Ok(()));
1061 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 2, 0), Ok(()));
1062 assert_eq!(
1063 sys_msync(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize * 2, 0),
1064 Ok(())
1065 );
1066
1067 sys_munmap(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize)
1069 .expect("unmap middle");
1070 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize, 0), Ok(()));
1071 assert_eq!(
1072 sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 3, starnix_uapi::MS_SYNC),
1073 error!(ENOMEM)
1074 );
1075 assert_eq!(
1076 sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 2, starnix_uapi::MS_SYNC),
1077 error!(ENOMEM)
1078 );
1079 assert_eq!(
1080 sys_msync(
1081 ¤t_task,
1082 (addr + *PAGE_SIZE).unwrap(),
1083 *PAGE_SIZE as usize * 2,
1084 starnix_uapi::MS_SYNC
1085 ),
1086 error!(ENOMEM)
1087 );
1088 assert_eq!(
1089 sys_msync(
1090 ¤t_task,
1091 (addr + (*PAGE_SIZE * 2)).unwrap(),
1092 *PAGE_SIZE as usize,
1093 0
1094 ),
1095 Ok(())
1096 );
1097
1098 assert_eq!(
1101 map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE),
1102 (addr + *PAGE_SIZE).unwrap()
1103 );
1104 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 3, 0), Ok(()));
1105 assert_eq!(sys_msync(¤t_task, addr, *PAGE_SIZE as usize * 2, 0), Ok(()));
1106 assert_eq!(
1107 sys_msync(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize * 2, 0),
1108 Ok(())
1109 );
1110 })
1111 .await;
1112 }
1113
1114 #[::fuchsia::test]
1116 async fn test_mremap_shrink_whole_range_from_end() {
1117 spawn_kernel_and_run(async |current_task| {
1118 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
1120 fill_page(¤t_task, addr, 'a');
1121 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1122
1123 assert_eq!(
1125 remap_memory(
1126 ¤t_task,
1127 addr,
1128 *PAGE_SIZE * 2,
1129 *PAGE_SIZE,
1130 0,
1131 UserAddress::default()
1132 ),
1133 Ok(addr)
1134 );
1135
1136 check_page_eq(¤t_task, addr, 'a');
1137 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1138 })
1139 .await;
1140 }
1141
1142 #[::fuchsia::test]
1144 async fn test_mremap_shrink_partial_range() {
1145 spawn_kernel_and_run(async |current_task| {
1146 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1148 fill_page(¤t_task, addr, 'a');
1149 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1150 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1151
1152 assert_eq!(
1154 remap_memory(
1155 ¤t_task,
1156 addr,
1157 *PAGE_SIZE * 2,
1158 *PAGE_SIZE,
1159 0,
1160 UserAddress::default()
1161 ),
1162 Ok(addr)
1163 );
1164
1165 check_page_eq(¤t_task, addr, 'a');
1166 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1167 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1168 })
1169 .await;
1170 }
1171
1172 #[::fuchsia::test]
1174 async fn test_mremap_shrink_across_ranges() {
1175 spawn_kernel_and_run(async |current_task| {
1176 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1179 assert_eq!(
1180 sys_munmap(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize),
1181 Ok(())
1182 );
1183 assert_eq!(
1184 map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE),
1185 (addr + *PAGE_SIZE).unwrap()
1186 );
1187
1188 fill_page(¤t_task, addr, 'a');
1189 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1190 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1191
1192 assert_eq!(
1194 remap_memory(
1195 ¤t_task,
1196 addr,
1197 *PAGE_SIZE * 3,
1198 *PAGE_SIZE,
1199 0,
1200 UserAddress::default()
1201 ),
1202 Ok(addr)
1203 );
1204
1205 check_page_eq(¤t_task, addr, 'a');
1206 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1207 check_unmapped(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap());
1208 })
1209 .await;
1210 }
1211
1212 #[::fuchsia::test]
1214 async fn test_mremap_grow_in_place() {
1215 spawn_kernel_and_run(async |current_task| {
1216 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1218 fill_page(¤t_task, addr, 'a');
1219 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1220 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1221 assert_eq!(
1222 sys_munmap(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE as usize),
1223 Ok(())
1224 );
1225
1226 assert_eq!(
1228 remap_memory(
1229 ¤t_task,
1230 addr,
1231 *PAGE_SIZE,
1232 *PAGE_SIZE * 2,
1233 0,
1234 UserAddress::default()
1235 ),
1236 Ok(addr)
1237 );
1238
1239 check_page_eq(¤t_task, addr, 'a');
1240
1241 check_page_ne(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1244
1245 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1246 })
1247 .await;
1248 }
1249
1250 #[::fuchsia::test]
1252 async fn test_mremap_grow_maymove() {
1253 spawn_kernel_and_run(async |current_task| {
1254 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1256 fill_page(¤t_task, addr, 'a');
1257 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1258 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1259
1260 let new_addr = remap_memory(
1262 ¤t_task,
1263 addr,
1264 *PAGE_SIZE * 2,
1265 *PAGE_SIZE * 3,
1266 MREMAP_MAYMOVE,
1267 UserAddress::default(),
1268 )
1269 .expect("failed to mremap");
1270
1271 assert_ne!(new_addr, addr, "mremap did not move the mapping");
1272
1273 check_unmapped(¤t_task, addr);
1275 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1276
1277 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1279
1280 check_page_eq(¤t_task, new_addr, 'a');
1282 check_page_eq(¤t_task, (new_addr + *PAGE_SIZE).unwrap(), 'b');
1283
1284 check_page_ne(¤t_task, (new_addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1286 })
1287 .await;
1288 }
1289
1290 #[::fuchsia::test]
1292 async fn test_mremap_shrink_fixed() {
1293 spawn_kernel_and_run(async |current_task| {
1294 let dst_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
1296 fill_page(¤t_task, dst_addr, 'y');
1297 fill_page(¤t_task, (dst_addr + *PAGE_SIZE).unwrap(), 'z');
1298
1299 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 3);
1301 fill_page(¤t_task, addr, 'a');
1302 fill_page(¤t_task, (addr + *PAGE_SIZE).unwrap(), 'b');
1303 fill_page(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1304
1305 let new_addr = remap_memory(
1307 ¤t_task,
1308 addr,
1309 *PAGE_SIZE * 2,
1310 *PAGE_SIZE,
1311 MREMAP_MAYMOVE | MREMAP_FIXED,
1312 dst_addr,
1313 )
1314 .expect("failed to mremap");
1315
1316 assert_eq!(new_addr, dst_addr, "mremap did not move the mapping");
1317
1318 check_unmapped(¤t_task, addr);
1320 check_unmapped(¤t_task, (addr + *PAGE_SIZE).unwrap());
1321
1322 check_page_eq(¤t_task, (addr + (*PAGE_SIZE * 2)).unwrap(), 'c');
1324
1325 check_page_eq(¤t_task, new_addr, 'a');
1327
1328 check_page_eq(¤t_task, (new_addr + *PAGE_SIZE).unwrap(), 'z');
1330 })
1331 .await;
1332 }
1333
1334 #[::fuchsia::test]
1336 async fn test_mremap_clobber_memory_mapping() {
1337 spawn_kernel_and_run(async |current_task| {
1338 let dst_memory = MemoryObject::from(zx::Vmo::create(2 * *PAGE_SIZE).unwrap());
1339 dst_memory.write(&['x' as u8].repeat(*PAGE_SIZE as usize), 0).unwrap();
1340 dst_memory.write(&['y' as u8].repeat(*PAGE_SIZE as usize), *PAGE_SIZE).unwrap();
1341
1342 let dst_addr = current_task
1343 .mm()
1344 .unwrap()
1345 .map_memory(
1346 DesiredAddress::Any,
1347 dst_memory.into(),
1348 0,
1349 2 * (*PAGE_SIZE as usize),
1350 ProtectionFlags::READ,
1351 Access::rwx(),
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}