feat: implement per-process environment variables (AI)
- Created env.c/h: key=value store with ENV_MAX_VARS=32 entries per process. Supports get, set, unset, and copy operations. - Added env_block_t and cwd[128] fields to process_t struct. - process_create() initializes CWD=/ by default. - Fork inherits environment via memcpy of the entire process_t. - Added SYS_GETENV (8) and SYS_SETENV (9) system calls. - Created env-test user app that verifies: CWD default, set/get, and inheritance across fork. - Updated kernel.c to launch 'sh' as init process (for next task). - Updated README.md to check off environment variables task. Tested: env-test reads CWD=/, sets TEST=hello, reads it back, forks child which inherits TEST=hello. All verified via QEMU.
This commit is contained in:
123
apps/env-test/env-test.S
Normal file
123
apps/env-test/env-test.S
Normal file
@@ -0,0 +1,123 @@
|
||||
#
|
||||
# env-test: Tests environment variable syscalls.
|
||||
#
|
||||
# 1. Gets CWD (should be "/")
|
||||
# 2. Sets TEST=hello
|
||||
# 3. Gets TEST (should be "hello")
|
||||
# 4. Forks - child gets TEST, verifies it was copied
|
||||
# 5. Both print results and exit
|
||||
#
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
|
||||
.equ SYS_EXIT, 0
|
||||
.equ SYS_WRITE, 1
|
||||
.equ SYS_FORK, 3
|
||||
.equ SYS_WAITPID, 6
|
||||
.equ SYS_GETENV, 8
|
||||
.equ SYS_SETENV, 9
|
||||
|
||||
# Helper: write a string (addr in %ecx, len in %edx) to stdout
|
||||
.macro WRITE_STR addr, len
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx
|
||||
movl \addr, %ecx
|
||||
movl \len, %edx
|
||||
int $0x80
|
||||
.endm
|
||||
|
||||
_start:
|
||||
# 1. Get CWD env var
|
||||
movl $SYS_GETENV, %eax
|
||||
movl $key_cwd, %ebx
|
||||
movl $buf, %ecx
|
||||
movl $128, %edx
|
||||
int $0x80
|
||||
|
||||
# Print "CWD="
|
||||
WRITE_STR $label_cwd, $4
|
||||
# Print the value (length returned in eax)
|
||||
movl %eax, %edx # length
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx
|
||||
movl $buf, %ecx
|
||||
int $0x80
|
||||
WRITE_STR $newline, $1
|
||||
|
||||
# 2. Set TEST=hello
|
||||
movl $SYS_SETENV, %eax
|
||||
movl $key_test, %ebx
|
||||
movl $val_hello, %ecx
|
||||
int $0x80
|
||||
|
||||
# 3. Get TEST
|
||||
movl $SYS_GETENV, %eax
|
||||
movl $key_test, %ebx
|
||||
movl $buf, %ecx
|
||||
movl $128, %edx
|
||||
int $0x80
|
||||
|
||||
# Print "TEST="
|
||||
WRITE_STR $label_test, $5
|
||||
movl %eax, %edx
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx
|
||||
movl $buf, %ecx
|
||||
int $0x80
|
||||
WRITE_STR $newline, $1
|
||||
|
||||
# 4. Fork
|
||||
movl $SYS_FORK, %eax
|
||||
int $0x80
|
||||
testl %eax, %eax
|
||||
jz .child
|
||||
|
||||
.parent:
|
||||
pushl %eax # save child PID
|
||||
WRITE_STR $msg_parent, $15
|
||||
|
||||
# Wait for child
|
||||
popl %ebx
|
||||
movl $SYS_WAITPID, %eax
|
||||
int $0x80
|
||||
|
||||
# Exit
|
||||
movl $SYS_EXIT, %eax
|
||||
movl $0, %ebx
|
||||
int $0x80
|
||||
|
||||
.child:
|
||||
# Child: get TEST to verify it was inherited
|
||||
movl $SYS_GETENV, %eax
|
||||
movl $key_test, %ebx
|
||||
movl $buf, %ecx
|
||||
movl $128, %edx
|
||||
int $0x80
|
||||
|
||||
# Print "Child TEST="
|
||||
WRITE_STR $label_child_test, $11
|
||||
movl %eax, %edx
|
||||
movl $SYS_WRITE, %eax
|
||||
movl $1, %ebx
|
||||
movl $buf, %ecx
|
||||
int $0x80
|
||||
WRITE_STR $newline, $1
|
||||
|
||||
# Exit
|
||||
movl $SYS_EXIT, %eax
|
||||
movl $0, %ebx
|
||||
int $0x80
|
||||
|
||||
.section .rodata
|
||||
key_cwd: .asciz "CWD"
|
||||
key_test: .asciz "TEST"
|
||||
val_hello: .asciz "hello"
|
||||
label_cwd: .ascii "CWD="
|
||||
label_test: .ascii "TEST="
|
||||
label_child_test: .ascii "Child TEST="
|
||||
msg_parent: .ascii "Parent done!\n\0\0"
|
||||
newline: .ascii "\n"
|
||||
|
||||
.section .bss
|
||||
buf: .space 128
|
||||
Reference in New Issue
Block a user