Skip to content

Fix FDT being overwritten #54 - #55

Merged
36 commits merged into
masterfrom
fix/smp-freeze
Oct 27, 2026
Merged

36 commits merged into
masterfrom
fix/smp-freeze

Conversation

@greatbridf

Copy link
Copy Markdown
Owner

Check #54 for more details.

Update rust toolchain version. The latest nightly doesn't support json
targets without passing some argument to rustc. So don't use the latest.

concat_ident! is removed in favor of concat!, and we are actually
already using that.  So remove the unstable feature declaration in
src/lib.rs as well.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Change the type of target width items to numbers according to the
specifications.

Signed-off-by: greatbridf <greatbridf@icloud.com>
(cherry picked from commit a5f6349)
Signed-off-by: greatbridf <greatbridf@icloud.com>
External interrupts were unimplemented on loongarch64: the trap context
mapped HWI0..HWI5 to a `todo!()`, so no driver could ever be woken by
hardware.  This made the serial port unusable for input -- the read
worker armed the UART's receive interrupt and then waited forever.

On the QEMU virt machine the path from a device to the CPU is

    device -> PCH-PIC line -> EIOINTC vector -> CPU HWI line

The PCH-PIC is an ordinary MMIO block at 0x1000_0000; the EIOINTC lives
in the IOCSR address space and is accessed with iocsrrd/iocsrwr.  Add a
small interrupt module that programs both: every EIOINTC vector is
routed to HWI1 (matching the interrupt controller's `interrupts = <3>`
device tree entry) and to CPU 0, and PCH-PIC lines are additionally
routed to the vector of the same number through HTMSI_VEC.

Lines stay masked until a handler exists.  register_irq_handler() now
unmasks the corresponding PCH-PIC line through the HAL on loongarch64,
so an interrupt cannot be delivered before the kernel can service it,
and enabling a line clears any stale EIOINTC pending bit first.

dispatch_irq() acknowledges the pending bit in COREISR before invoking
the handler, so a peripheral that keeps its line asserted simply
re-raises the interrupt until it is drained.  Only vectors 0..32 are
dispatched; the remaining vectors belong to the PCI MSI controller,
which is not supported yet, so they are acknowledged and dropped.

With this in place UART0 (PCH-PIC line 2) delivers receive interrupts
and serial input works under QEMU: typed commands are echoed and
executed, and the system stays idle at the prompt instead of spinning
on a level-triggered interrupt.

Assisted-by: deepseek-flash
Signed-off-by: greatbridf <greatbridf@icloud.com>
Rearrange code to pass args instead of by envs, no functionality
changes.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
- printf -v is non-standard, use var=$(printf) instead.
- expect is not installed in the runner. install it manually

Signed-off-by: greatbridf <greatbridf@icloud.com>
Add PLATFORM in Makefile to indicate the actual system setup. Put build
image script of each platforms to dedicated folders. This makes creating
test setups easier.

Signed-off-by: greatbridf <greatbridf@icloud.com>
No functional change.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Instead, add an example vscode settings file for IDE use.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
Add a project-scoped Pi skill that guides kernel issue reproduction,
root-cause analysis, fix verification, and PR submission. The skill
requires GH_TOKEN before doing any work and uses phase-gated subagent
handoffs.

Split the detailed protocol into phase-specific reference documents so
only the relevant guidance is loaded for each phase.

Signed-off-by: greatbridf <greatbridf@icloud.com>
- Add script/backtrace to translate backtraces.
- Add a cut sign in the kernel panic routine to indicate the start of
  stack backtrace.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Inode and superblock rework:

Remove old Inode trait as it used to undertake too much responsibility.
The new method use three new traits: InodeOps is used to acquire generic
inode attributes. InodeFileOps and InodeDirOps handle file and directory
requests respectively. All the three have async fn trait methods and
don't need to be ?Sized. Then, we implement Inode, InodeFile and
InodeDir for the implementors of the three "Ops" traits, erasing their
actual type and provide generic dyn interface by wrapping the futures in
boxes. We should provide an io worker? or some io context with an
allocator for futures to reduce the overhead of io requests, or come up
with some better ideas?

For inode usage, we introduce InodeRef and InodeUse. InodeRef is a
simple wrapper for Weak<impl Inode> and InodeUse for Arc<impl Inode>.
This helps us use them better as we can't define impls for Arc<dyn
Inode>'s as they are foreign types. We also provide some more helper
methods for them.

After the change, we don't impose ANY structural restriction except for
the spinlock wrapped InodeInfo. The InodeInfo struct design might need
rethinking but the current implementation seems to be fine aside from
unnecessary locks when we try to access some of its fields but this
shouldn't be a VERY big problem and very urgent...

Similar changes are also made to superblock traits and types. But for
the superblock objects, we use a SuperBlockComplex struct to store
common fields such as whether the superblock is read only, their device
id and so on. Also the structs have a superblock rwsem inside. But we
haven't decided how to use that (such as whether we should acquire the
lock and pass it to the inode methods) and even whether they should
exist and be there. This will need further thinking so we put this off
for now...

Filesystem rework:

Rework tmpfs, fatfs and procfs with the new technology mentioned above,
leaving the old ext4 unchanged. The current implementation of ext4 uses
some "random" library from the "camp". Its code hasn't been fully
reviewed for time reasons but seems to be rather "problematic"... We
might rewrite the whole module later and the page cache subsystem
requires fully reworking as well. So we put this work off as well.

Block device and other parts rework:

Wraps PageCacheBackend, MountCreator and BlockRequestQueue with
async_trait to provide dyn compatible async functions. Dentry walking
functions are also put to the heap since they are recursive functions...
This has similar problems to the inode traits, ugly solution. Further
optimization is required.

Signed-off-by: greatbridf <greatbridf@icloud.com>
The old path walking algorithm requires recursion, which is not
supported in async rust. So we boxed them all as a temporary solution in
previous commits. This would introduce mass overhead even for fast path
walks just because we might sleep in `readlink()` and `lookup()` calls.

The new proposed method is to break the walk into several phases similar
to that in Linux: RCU walk and REF walk. The RCU walk will hold the RCU
lock and never blocks so the function itself can be non-async. If we hit
non-present dentries, we will fallback to REF walk. In REF walks, we
clone the Arcs and consult to the VFS layer for an accurate answer.

Note that in both the two methods mentioned above, symlinks are not
handled and will be returned directly with all path components left
untouched. We have a dedicated async function to follow the symlinks by
recursive calling the walk function. This can be slow and won't be
called frequently. So we wrapped the function with `Box::pin()` to break
the recursion chain. After the symlink resolution is done, we return to
the original position and continue the walk.

We found that the association of an inode to a dentry is one way. So the
`data` RCUPointer field is actually unnecessary and we can use the atomic
dentry type to sync readers with the writer. This way we can eliminate
`DentryData` allocations and improve performance.

We also introduced a new RCU read lock syntax. In the RCU walk mentioned
above, we need to store dentry references protected by some RCU read lock.
With the old syntax, we can't express the lifetime associtated by the
common RCU read lock. The new syntax provides a `rcu_read_lock()` method
to acquire the RCU read lock. The lock returned has a associated lifetime
so we can use it in the RCU session.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
If we have invalid format, we should print a None instead of panicking.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
Introduce the new page locking mechanism to ensure exclusiveness of
pages when we access them. The underlying locks are not implemented yet
for now because we will change the paging structs in the following few
patches.

Introduce a new `PageExcl` struct representing a page that conforms with
Rust's ownership rules. The page owned exclusively can be accessed
without taking page locks.

Remove the `MemoryBlock` structs as they are not easy to use and
represent barely no semantic meanings.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Separate old UserTLS into UserTLS and UserTLSDescriptor.

UserTLS is for threads to hold infomation about its storage. Descriptors
are used in clone syscalls.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
Introduce `Zone`s: a Zone is a region of physical memory that all share
the same NUMA node. The Zone will hold all RawPage structs. Buddy
allocator will now store a reference to the zone that hold all its
pages. Thus, we make the buddy allocator independent of underlying
physical page frame management framework.

Remove unnecessary page flags and structs.

Signed-off-by: greatbridf <greatbridf@icloud.com>
- Bump rust compiler version to nightly-2026-01-09.
- Inode rework: add a generic Inode struct.
- Add a macro to help function tweaks.
- PageCache rework: reduce complexity and try to decouple.
- Adapt fat32, tmpfs to the new page cache system.
- Change the way we process mapped pages and load ELF executables.
- Refine handling flags in `MMArea::handle_mmap`.

Signed-off-by: greatbridf <greatbridf@icloud.com>
- Remove struct `Page` and add `Folio`s to represent adjacent pages.
- Introduce `Zone`s similar to that in Linux. Looking forward to
  removing all occurrence of `ArchPhysAccess` and so on.
- Adapt existing code to new `Folio` interface in a dirty and rough way.

Signed-off-by: greatbridf <greatbridf@icloud.com>
No functional changes

- Add `{extern_,}symbol_addr` macro to retrieve symbol address.
- Remove manual impl Send and Sync for RawPage
- Make elided '_ lifetimes in return types explicit
- Suppress unused warnings by allowing them
- Remove really unused functions
- Refactor `println_trace` macro to suppress unused variable warnings

Signed-off-by: greatbridf <greatbridf@icloud.com>
Make print message prettier. Also panic when we have an error.

Signed-off-by: greatbridf <greatbridf@icloud.com>
- thd.exit() will set thd.dead and send it to the reaper
- delay the release of process mm until we reap it
- extract futex logic out of exit and exec routine

Signed-off-by: greatbridf <greatbridf@icloud.com>
- Use intrusive lists to store and organize the process hierarchy.
- Remove `FileArray::open_console()`. Do it in the init script instead.
- Fix open logic: acquire controlling terminals only if O_NOCTTY is not
  set. Put this into TerminalFile::open().
- Send SIGHUP and then SIGCONT to foreground pgroup procs when the
  controlling terminal is dropped.
- Set the controlling terminal of sessions in Terminal.
- Limit max line width to 80. Format some codes.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Reformat the files with new the format style to make the real changes
clearer.

Signed-off-by: greatbridf <greatbridf@icloud.com>
We already have `FDT.present_ram().free_ram()`. Remove the impl in
`ArchMemory` to avoid confusion.

Signed-off-by: greatbridf <greatbridf@icloud.com>
- Add `extern_symbol_value` to retrieve far relative symbol values.
- Get `BSS_LENGTH` and `__kernel_end` using `extern_symbol_addr`.
- Get `_ap_start` using `extern_symbol_value`.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
With current ldscript, linkers will put vdso data after `__kernel_end`,
which is buggy since we use the symbol to indicate the end of our kernel
image and newly allocated pages may overwrite those positions.

Change by place the vdso inside REGION_DATA. Remove old VDSO memory
region. Align .data section end to page size border.

Add a helper macro to retrieve .vdso section symbol addresses.

Signed-off-by: greatbridf <greatbridf@icloud.com>
Strip out the memory used by the kernel and FDT data out of free memory
block returned by FDT.

Closes: #54 ("Random kernel freezing on process creation / exiting")
Fixes: 4351cf5 ("partial work: fix riscv64 bootstrap")
Signed-off-by: greatbridf <greatbridf@icloud.com>
Using *const (), no bytes are written to the position, which might
result in uninitialized memory access.

Fixes: ebd3d12 ("change(x86): optimize bootstrap code, remove kinit.cpp")
Fixes: 191877a ("feat(hal): impl basic single hart bootstrap for riscv64")
Signed-off-by: greatbridf <greatbridf@icloud.com>
Signed-off-by: greatbridf <greatbridf@icloud.com>
This can shorten qemu memory map.

Signed-off-by: greatbridf <greatbridf@icloud.com>
@greatbridf greatbridf closed this pull request by merging all changes into master in b8c30a3 Oct 27, 2026
@greatbridf
greatbridf deleted the fix/smp-freeze branch October 27, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant