Commit Graph

2349 Commits

Author SHA1 Message Date
bjorn3 3d1188cf1e Introduce Response::as_regular 2026-02-08 12:54:04 +01:00
bjorn3 99ff55ee1b Demux results as soon as we receive them from a user scheme 2026-02-08 12:50:53 +01:00
bjorn3 f88cbf96ee Remove unnecessary clones and pass CallerCtx to call() 2026-02-08 12:46:08 +01:00
bjorn3 5c6af01a9a Remove two unnecessary uses of spin::Once 2026-02-07 13:14:48 +01:00
bjorn3 e14a20aae2 Mark two functions as private 2026-02-07 12:59:24 +01:00
bjorn3 4e41ed987a Fix /scheme/sys/context header 2026-02-07 12:31:42 +01:00
bjorn3 2f8a3b3d67 Remove unused SchemeNamespace type 2026-02-06 22:05:42 +01:00
bjorn3 f334e760bb Remove ens field from Context
It is no longer used due to the capability rework.
2026-02-06 22:00:18 +01:00
bjorn3 9f218c5b3a Fix assertion in Args::args() 2026-02-06 21:07:16 +01:00
bjorn3 7ff1898765 Fix a couple of warnings 2026-02-06 20:54:42 +01:00
bjorn3 6ddd0a9098 Replace scheme::schemes() with scheme::get_scheme()
We never need to iterate over all schemes. We only ever need to access
individual schemes.
2026-02-06 20:54:42 +01:00
bjorn3 ace9038720 Reduce visibility of a couple of methods 2026-02-06 20:34:16 +01:00
Jeremy Soller 2055a205f1 Remove legacy path message 2026-01-29 10:12:04 -07:00
Ibuki Omatsu 5ac00f5533 Remove namespace management from the kernel. 2026-01-20 20:43:34 -07:00
Jeremy Soller 1c850605d0 Only read time once during context switch 2026-01-20 14:18:33 -07:00
Jeremy Soller 81a49d211b Fix potential preempt guard deadlock 2026-01-20 13:58:31 -07:00
Anhad Singh 7d42e8d966 fix(switch): deadlock
During the snapshot shown, interrupts would be _disabled_ on both CPUs and both
would have have the _same_ address space (i.e.
`PercpuBlock::current().current_addrsp`).

```rs
// CPU 0                                                                                             CPU 1 (inside `context::switch()`)
// ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// let guard = current_addrsp.acquire_write()
// let flusher = Flusher::with_cpu_set(&addrsp.used_by, &current_addrsp.tlb_ack);
// ...
// drop(flusher); // Flusher::flush()
//     // send IPI to CPU 1 as it is in the `active_set`
//     shootdown_tlb_ipi(Some(1));
//                                                                                                    percpu::switch_arch_hook();
//     // spin until TLB shootdown IPI has been acknowledged by CPU 1                                 // acquire_read() to remove the CPU from the `used_by` set in `prev_addrsp`
//     while ackword < affected_cpu_count                                                             prev_addrsp.acquire_read()
//         PercpuBlock::current().maybe_handle_tlb_shootdown();
//         spin_loop();
//     }
// drop(guard);
```

Now CPU 0 will spin _until_ CPU 1 has acknowledged the IPI. However, CPU 1 has
interrupts disabled and is in the middle of a context switch. To complete the
context switch it needs to remove itself from the `used_by` set in
`prev_addrsp` (which is the current address space atm). To do that it needs to
`acquire_read()` lock but it cannot since it is held by CPU 0 and won't release
it until CPU 1 has acknowledged the IPI; creating a deadlock.

Also note:

```rs
// src/context/memory.rs
// NOTE: Lock must be held, which must be guaranteed by the caller.
pub fn flush(&mut self) {
```

Here is some output from GDB to back this up:

```
pwndbg> info threads
  Id   Target Id                    Frame
  1    Thread 1.1 (CPU#0 [running]) core::sync::atomic::atomic_compare_exchange_weak<usize> (dst=0xffffff7f801972f0, old=0, new=1, success=core::sync::atomic::Ordering::Acquire, failure=core::sync::atomic::Ordering::Relaxed)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/sync/atomic.rs:4100
  2    Thread 1.2 (CPU#1 [running]) kernel::context::memory::Flusher::flush (self=0xffff80004212f4b8) at src/context/memory.rs:2827
  3    Thread 1.3 (CPU#2 [running]) spin::rwlock::RwLock<kernel::context::context::Context, spin::relax::Spin>::write<kernel::context::context::Context, spin::relax::Spin> (self=0xffffff7f801a99c0)
    at /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.8/src/rwlock.rs:239
* 4    Thread 1.4 (CPU#3 [running]) 0xffffffff80059cf9 in kernel::context::memory::AddrSpaceWrapper::acquire_read (self=0xffffff7f80188110)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs:25
pwndbg> p kernel::context::arch::CONTEXT_SWITCH_LOCK
$1 = core::sync::atomic::AtomicBool {
  v: core::cell::UnsafeCell<u8> {
    value: 1
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[0].p.value).wants_tlb_shootdown.v.value
$2 = 0
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[1].p.value).wants_tlb_shootdown.v.value
$3 = 0
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[2].p.value).wants_tlb_shootdown.v.value
$4 = 1
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[3].p.value).wants_tlb_shootdown.v.value
$5 = 0
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[3].p.value).current_addrsp
$6 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80188100
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[2].p.value).current_addrsp
$7 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80188100
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[1].p.value).current_addrsp
$8 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80188100
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
pwndbg> p (*kernel::percpu::ALL_PERCPU_BLOCKS[0].p.value).current_addrsp
$9 = core::cell::RefCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
  borrow: core::cell::Cell<isize> {
    value: core::cell::UnsafeCell<isize> {
      value: 0
    }
  },
  value: core::cell::UnsafeCell<core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>> {
    value: core::option::Option<alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global>>::Some(alloc::sync::Arc<kernel::context::memory::AddrSpaceWrapper, alloc::alloc::Global> {
        ptr: core::ptr::non_null::NonNull<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>> {
          pointer: 0xffffff7f80133ac8
        },
        phantom: core::marker::PhantomData<alloc::sync::ArcInner<kernel::context::memory::AddrSpaceWrapper>>,
        alloc: alloc::alloc::Global
      })
  }
}
```

```
pwndbg> thread 4
[Switching to thread 4 (Thread 1.4)]
25	in /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs
pwndbg> info threads
  Id   Target Id                    Frame
  1    Thread 1.1 (CPU#0 [running]) core::sync::atomic::atomic_compare_exchange_weak<usize> (dst=0xffffff7f801972f0, old=0, new=1, success=core::sync::atomic::Ordering::Acquire, failure=core::sync::atomic::Ordering::Relaxed)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/sync/atomic.rs:4100
  2    Thread 1.2 (CPU#1 [running]) kernel::context::memory::Flusher::flush (self=0xffff80004212f4b8) at src/context/memory.rs:2827
  3    Thread 1.3 (CPU#2 [running]) spin::rwlock::RwLock<kernel::context::context::Context, spin::relax::Spin>::write<kernel::context::context::Context, spin::relax::Spin> (self=0xffffff7f801a99c0)
    at /root/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.8/src/rwlock.rs:239
* 4    Thread 1.4 (CPU#3 [running]) 0xffffffff80059cf9 in kernel::context::memory::AddrSpaceWrapper::acquire_read (self=0xffffff7f80188110)
    at /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs:25
pwndbg> thread 4
[Switching to thread 4 (Thread 1.4)]
25	in /mnt/redox/prefix/x86_64-unknown-redox/sysroot/lib/rustlib/src/rust/library/core/src/../../stdarch/crates/core_arch/src/x86/sse2.rs
pwndbg> bt
```

This is *after* everything freezes.

For relibc tests, if I run `while true; do
/root/relibc-tests/pthread/once; done` it eventually does freeze up and
does so at the same location:

```
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ THREADS (4 TOTAL) ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  ► 1   "" stopped: 0xffffffff800750a2 <kernel::context::switch::switch+1282>
    4   "" stopped: 0xffffffff80074d5a <kernel::context::switch::switch+442>
    3   "" stopped: 0xffffffff80059cf9 <kernel::context::context::Context::set_addr_space+217>
    2   "" stopped: 0xffffffff80020839 <kernel::context::memory::Flusher::flush+361>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
```

Related: https://gitlab.redox-os.org/redox-os/kernel/-/issues/175

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-01-19 15:21:13 +11:00
Pascal Reich a919d2626b Inline Documentation Fixes 2026-01-10 16:19:34 -07:00
Jeremy Soller ea06685903 Do not allow recursively registering the same event queue 2026-01-09 12:08:16 -07:00
Anhad Singh a245e49e75 fix(syscalls/futex): premature timeout
Previously, if a futex with a timeout was woken up (even via
`futex_wake`), it was treated as though the timeout had expired. When
the timeout expires, the scheduler sets `wake` to `None` and unblocks
the process. Hence if `wake` is `None` and if a timeout was given to
futex, it has expired. Otherwise the process was woken up by
`futex_wake`.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-01-07 14:45:01 +11:00
Anhad Singh 5ccd2414af fix(context/memory): incorrect remaining_src_span
The `AddrSpaceWrapper::r#move` is used by `mremap` to move, expand or
shrink existing mappings.

`src_span.count`: Size of old region in pages
`new_page_count`: Size of new region in pages

Fixes the following panic when running `cargo`:

```
KERNEL PANIC: panicked at src/context/memory.rs:1969:9:
assertion failed: self.info.can_extract(false)
  FP ffff80000cbbf2c0: PC ffffffff8004ced5
    FFFFFFFF8004CD50+0185
    kernel::panic::panic_handler_inner
  FP ffff80000cbbf3a0: PC ffffffff8004ac99
  FP ffff80000cbbf3b0: PC ffffffff800a34df
  FP ffff80000cbbf3e0: PC ffffffff800a34b4
  FP ffff80000cbbf430: PC ffffffff8001c029
    FFFFFFFF8001BF10+0119
    kernel::context::memory::Grant::extract
  FP ffff80000cbbf4a0: PC ffffffff800181ac
    FFFFFFFF80016D30+147C
    kernel::context::memory::AddrSpaceWrapper::move
  FP ffff80000cbbfd30: PC ffffffff80037c08
    FFFFFFFF80035660+25A8
    kernel::syscall::syscall
  FP ffff80000cbbfe90: PC ffffffff8008efbf
    FFFFFFFF8008EF10+00AF
    __inner_syscall_instruction
  FP ffff80000cbbff50: PC ffffffff80085d33
    FFFFFFFF80085CF0+0043
    kernel::arch::x86_64::interrupt::syscall::syscall_instruction
  0000000000004455: GUARD PAGE
CPU #2, CID 0xffffff7f80133690
NAME: /scheme/initfs/bin/redoxfs, DEBUG ID: 43
SYSCALL: mremap(0x2177F000, 0x8000, 0x0, 0xC7000, 0x60000)
HALT
```

```
mremap_flags = MremapFlags(
    0x0,
)
prot_flags = MapFlags(
    PROT_WRITE | PROT_READ,
)
```

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2026-01-03 22:56:03 +11:00
Wildan M 92132132c1 Implement clock_getres and handle path to time scheme 2025-12-21 05:24:13 +07:00
Ibuki Omatsu e30ed9ab6a Introduce syscall6. Add unlinkat and remove unlink and rmdir. 2025-12-17 18:31:04 -07:00
Anhad Singh d9eae6bb75 fix(sync/wait_condition): deadlock in WaitCondition::wait
Instead of using a simple switch to determine if preemption is enabled
(`is_preemptable: bool`), a counter is used instead. This handles the
case where a function holding a `PreemptGuard` calls another function
that creates a new `PreemptGuard`.

Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-12-15 13:05:29 +11:00
bjorn3 62a572a0f0 Use compiler-builtins for the memcpy family of functions 2025-12-14 16:38:04 +01:00
bjorn3 c089667ade Remove support for the legacy packet user schemes 2025-12-13 15:52:30 +01:00
bjorn3 3091f40c13 Warn against opening a legacy scheme version 2025-12-13 15:12:01 +01:00
Wildan M e06f908b1b Add CI workflow 2025-12-11 01:07:33 +07:00
bjorn3 3bf880e008 Correctly handle MAP_FIXED with a zero address 2025-12-09 23:09:19 +01:00
bjorn3 5a11067f10 Support non-fixed and anonymous remote mmap 2025-12-09 20:55:19 +01:00
bjorn3 58a362844a Add a binary variant for the filetable read operation
This is a lot easier to parse in no_alloc scenarios than the current
textual format. This would help with moving the cloexec handling from
relibc to redox-rt.
2025-12-08 21:55:03 +01:00
Anhad Singh ac713a061c misc(scheme/user): treat all spurious wakeups as signal
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-28 15:24:32 +11:00
Anhad Singh 45aae5f963 misc(scheme/user): use preempt guard
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-27 16:23:31 +11:00
Anhad Singh b2c9e5defd misc(scheme/user): unblock the process *after* setting the state
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-27 16:21:03 +11:00
Anhad Singh 4ff82ad8b5 fix(scheme/user): deadlocks inside call_extended_inner
Signed-off-by: Anhad Singh <andypython@protonmail.com>
2025-11-27 14:39:14 +11:00
Jeremy Soller 27465b6132 Make CPU announcements debug level 2025-11-23 07:41:09 -07:00
Jeremy Soller 7ffc046d46 Enable serial interrupts on aarch64 ACPI 2025-11-21 08:39:38 -07:00
Jeremy Soller e3cafc975f Format 2025-11-17 17:41:04 -07:00
Jeremy Soller 91ba44e2fa Implement F_DUPFD_CLOEXEC 2025-11-17 17:40:39 -07:00
aarch 2bdc5d2109 Implement kfpath for dtb kernel scheme 2025-11-15 17:45:39 +00:00
Jeremy Soller e14f935063 Ensure pipe is_alive is set before triggering event or condition 2025-11-14 20:59:44 -07:00
Jeremy Soller 2d9f2015d0 Add upper table fds to kernel.proc filetable 2025-11-14 15:06:37 -07:00
Jeremy Soller 42f9f04188 Require kfpath implementation, add to acpi scheme 2025-11-14 14:19:33 -07:00
Jeremy Soller 61ad67fbfe Improve display of upper table in iostat 2025-11-14 13:55:55 -07:00
4lDO2 33dbf2458e only clear RC_USED_NOT_FREE with freelist locked 2025-11-14 20:06:18 +01:00
4lDO2 96552163f6 Clear RC_USED_NOT_FREE even for contention case. 2025-11-14 20:06:18 +01:00
4lDO2 dc33c67997 Fix potential refcount underflow from fetch_sub. 2025-11-14 20:06:18 +01:00
Jeremy Soller cbea1aca3d Implement kfpath on more schemes 2025-11-14 11:36:49 -07:00
Jeremy Soller 64ea4251ee Debug SYS_MREMAP 2025-11-13 15:55:02 -07:00
Jeremy Soller e6edef2d8e Downgrade addrspace outside futex loop 2025-11-12 10:34:18 -07:00