Files
claude-os/apps/fork-test/fork-test.S
AI 42328ead0b feat: implement fork system call with deep address space cloning (AI)
- Added paging_clone_directory_from(): deep-copies user-space pages so
  parent and child have independent memory. Kernel pages are shared.
- Fixed process_fork() to accept registers_t* for accurate child state,
  and to clone from the parent's page directory (not the kernel's).
- Refactored process_exit() to properly context-switch to next process
  using new process_switch_to_user assembly stub (loads full registers_t
  and performs iret), instead of halting unconditionally.
- Fixed sys_waitpid() to use proper blocking: marks process BLOCKED,
  invokes scheduler, and resumes with exit code when child dies.
- Added SYSCALL_SWITCHED mechanism to prevent syscall_handler from
  clobbering the next process's EAX after a context switch.
- Created fork-test user app that validates fork + waitpid.
- Added docs/fork.md with architecture documentation.

Tested: fork-test creates child, both print messages, parent waits for
child exit (code 7), parent reaps and exits (code 0). hello-world also
verified to still work correctly after the process_exit refactor.
2026-02-23 12:42:02 +00:00

80 lines
1.7 KiB
ArmAsm

#
# fork-test: Tests the fork system call.
#
# 1. Calls SYS_FORK
# 2. Parent prints "Parent: pid=<pid>\n" and waits for child
# 3. Child prints "Child: pid=0\n" and exits with code 7
# 4. Parent exits with code 0
#
.section .text
.global _start
# System call numbers
.equ SYS_EXIT, 0
.equ SYS_WRITE, 1
.equ SYS_FORK, 3
.equ SYS_GETPID, 4
.equ SYS_WAITPID, 6
_start:
# Fork
movl $SYS_FORK, %eax
int $0x80
# EAX = 0 in child, child PID in parent
testl %eax, %eax
jz .child
.parent:
# Save child PID on the stack
pushl %eax
# Print "Parent\n"
movl $SYS_WRITE, %eax
movl $1, %ebx # fd = stdout
movl $parent_msg, %ecx
movl $parent_msg_len, %edx
int $0x80
# Waitpid for child
popl %ebx # child PID
movl $SYS_WAITPID, %eax
int $0x80
# EAX now has child's exit code (should be 7)
# Print "Reaped\n"
pushl %eax # save exit code
movl $SYS_WRITE, %eax
movl $1, %ebx
movl $reaped_msg, %ecx
movl $reaped_msg_len, %edx
int $0x80
popl %ebx # exit code (unused, exit with 0)
# Exit with code 0
movl $SYS_EXIT, %eax
movl $0, %ebx
int $0x80
.child:
# Print "Child\n"
movl $SYS_WRITE, %eax
movl $1, %ebx # fd = stdout
movl $child_msg, %ecx
movl $child_msg_len, %edx
int $0x80
# Exit with code 7
movl $SYS_EXIT, %eax
movl $7, %ebx
int $0x80
.section .rodata
parent_msg: .ascii "Parent\n"
.equ parent_msg_len, . - parent_msg
child_msg: .ascii "Child\n"
.equ child_msg_len, . - child_msg
reaped_msg: .ascii "Reaped\n"
.equ reaped_msg_len, . - reaped_msg