feat(kernel): add date and pwd user commands with syscall improvements

- Add date command implementation that displays current time in UTC format
- Add pwd command to print current working directory
- Update Makefile to build date and pwd as user programs with shared ELF loading
- Refactor syscall handling to use shared header definitions
- Remove KernelGreeting class from kernel startup sequence
- Update README and ROADMAP documentation for new user commands
- Add test assertions for date and pwd command output in test suite
- Introduce reusable command address space management in process.c
master
韩天峰 4 weeks ago
parent 0cfa577db1
commit 66184e775c
  1. 40
      examples/typephp-os/Makefile
  2. 29
      examples/typephp-os/README.md
  3. 5
      examples/typephp-os/ROADMAP.md
  4. 18
      examples/typephp-os/freestanding/abi/typephp_os_syscall.h
  5. 194
      examples/typephp-os/freestanding/process.c
  6. 3
      examples/typephp-os/project.yml
  7. 10
      examples/typephp-os/src/kernel.php
  8. 6
      examples/typephp-os/tools/test-qemu.sh
  9. 82
      examples/typephp-os/user/date.c
  10. 14
      examples/typephp-os/user/pwd.c
  11. 6
      examples/typephp-os/user/sh.c
  12. 12
      examples/typephp-os/user/syscall.h

@ -6,15 +6,16 @@ PAYLOAD_BIN := $(BUILD)/kernel64.bin
PAYLOAD_OBJECT := $(OBJECT_DIR)/kernel64-payload.o
KERNEL := $(BUILD)/typephp-os.elf
DISK := $(BUILD)/typephp-os.img
USER_COMMANDS := ls cd date pwd fault
USER_PROGRAMS := sh $(USER_COMMANDS)
USER_SH_ELF := $(BUILD)/sh.elf
USER_LS_ELF := $(BUILD)/ls.elf
USER_CD_ELF := $(BUILD)/cd.elf
USER_IMAGES := $(OBJECT_DIR)/sh-image.o $(OBJECT_DIR)/ls-image.o $(OBJECT_DIR)/cd-image.o
USER_COMMAND_ELFS := $(addprefix $(BUILD)/,$(addsuffix .elf,$(USER_COMMANDS)))
USER_IMAGES := $(addprefix $(OBJECT_DIR)/,$(addsuffix -image.o,$(USER_PROGRAMS)))
BOOTFLAGS := -m32 -O2 -ffreestanding -fno-pic -fno-pie \
-fno-stack-protector -Wall -Wextra
USER_CFLAGS := -m64 -O2 -ffreestanding -fno-builtin -fno-pic -fno-pie \
-fno-stack-protector -mno-red-zone -Wall -Wextra -Iuser
-fno-stack-protector -mno-red-zone -Wall -Wextra -Iuser -Ifreestanding/abi
USER_LDFLAGS := -m elf_x86_64 -nostdlib -static -T user/linker.ld
.PHONY: all payload objects disk run test clean
@ -43,41 +44,20 @@ $(OBJECT_DIR):
$(BOOTSTRAP_OBJECT): freestanding/boot.S | $(OBJECT_DIR)
gcc $(BOOTFLAGS) -c $< -o $@
$(OBJECT_DIR)/sh.o: user/sh.c user/syscall.h | $(OBJECT_DIR)
gcc $(USER_CFLAGS) -c $< -o $@
$(OBJECT_DIR)/ls.o: user/ls.c user/syscall.h | $(OBJECT_DIR)
gcc $(USER_CFLAGS) -c $< -o $@
$(OBJECT_DIR)/cd.o: user/cd.c user/syscall.h | $(OBJECT_DIR)
$(OBJECT_DIR)/%.o: user/%.c user/syscall.h freestanding/abi/typephp_os_syscall.h | $(OBJECT_DIR)
gcc $(USER_CFLAGS) -c $< -o $@
$(USER_SH_ELF): $(OBJECT_DIR)/sh.o user/linker.ld | $(BUILD)
ld $(USER_LDFLAGS) --defsym USER_BASE=0x2000000 -o $@ $<
$(USER_LS_ELF): $(OBJECT_DIR)/ls.o user/linker.ld | $(BUILD)
$(USER_COMMAND_ELFS): $(BUILD)/%.elf: $(OBJECT_DIR)/%.o user/linker.ld | $(BUILD)
ld $(USER_LDFLAGS) --defsym USER_BASE=0x2100000 -o $@ $<
$(USER_CD_ELF): $(OBJECT_DIR)/cd.o user/linker.ld | $(BUILD)
ld $(USER_LDFLAGS) --defsym USER_BASE=0x2200000 -o $@ $<
$(OBJECT_DIR)/sh-image.o: $(USER_SH_ELF) | $(OBJECT_DIR)
objcopy -I binary -O elf64-x86-64 -B i386:x86-64 \
--rename-section .data=.rodata.user_elf,alloc,load,readonly,data,contents \
--redefine-sym _binary_build_sh_elf_start=typephp_user_sh_elf_start \
--redefine-sym _binary_build_sh_elf_end=typephp_user_sh_elf_end $< $@
$(OBJECT_DIR)/ls-image.o: $(USER_LS_ELF) | $(OBJECT_DIR)
objcopy -I binary -O elf64-x86-64 -B i386:x86-64 \
--rename-section .data=.rodata.user_elf,alloc,load,readonly,data,contents \
--redefine-sym _binary_build_ls_elf_start=typephp_user_ls_elf_start \
--redefine-sym _binary_build_ls_elf_end=typephp_user_ls_elf_end $< $@
$(OBJECT_DIR)/cd-image.o: $(USER_CD_ELF) | $(OBJECT_DIR)
$(OBJECT_DIR)/%-image.o: $(BUILD)/%.elf | $(OBJECT_DIR)
objcopy -I binary -O elf64-x86-64 -B i386:x86-64 \
--rename-section .data=.rodata.user_elf,alloc,load,readonly,data,contents \
--redefine-sym _binary_build_cd_elf_start=typephp_user_cd_elf_start \
--redefine-sym _binary_build_cd_elf_end=typephp_user_cd_elf_end $< $@
--redefine-sym _binary_build_$*_elf_start=typephp_user_$*_elf_start \
--redefine-sym _binary_build_$*_elf_end=typephp_user_$*_elf_end $< $@
$(KERNEL): payload
objcopy -O binary $(PAYLOAD_ELF) $(PAYLOAD_BIN)

@ -6,8 +6,9 @@ PHP, libc, or libstdc++. TypePHP implements the startup self-check, a custom
Zend class, the prime-number demo, and filesystem services. Small C and
assembly layers provide the machine bootstrap, current kernel services, and
the temporary freestanding userspace programs.
The first userspace programs (`sh`, `ls`, and `cd`) are deliberately written
in freestanding C until tpc can target this small userspace ABI.
The first userspace programs (`sh`, `ls`, `cd`, `pwd`, and `date`) are
deliberately written in freestanding C until tpc can target this small
userspace ABI.
The architectural rules and staged plan are maintained in
[ROADMAP.md](ROADMAP.md).
@ -62,8 +63,8 @@ The build produces these useful files:
tpc;
- `build/typephp-os.elf`: the final Multiboot kernel accepted by QEMU;
- `build/typephp-os.img`: a persistent 32 MiB FAT16 disk image.
- `build/sh.elf`, `build/ls.elf`, and `build/cd.elf`: independent ELF64 Ring-3
programs built without libc.
- `build/sh.elf`, `build/ls.elf`, `build/cd.elf`, `build/pwd.elf`, and
`build/date.elf`: independent ELF64 Ring-3 programs built without libc.
Run the automated serial-output smoke test with:
@ -73,7 +74,7 @@ make test
The Makefile compiles the 32-bit Multiboot bootstrap externally because its
`-m32` ABI cannot participate in the 64-bit payload link. It also builds the
three deliberately small freestanding C userspace ELF files. All ordinary
five deliberately small freestanding C userspace ELF files. All ordinary
64-bit `.c`, `.cc`, and `.S` files remain in `project.yml` and use tpc's generic
`c-flags`, `cxx-flags`, and `asm-flags`. Generic same-ABI prebuilt objects can
be supplied with `objects`; this is how read-only copies of the user ELF files
@ -139,12 +140,15 @@ After the TypePHP self-check, the kernel validates and loads `sh.elf`, installs
a 64-bit TSS and an IDT gate, and enters Ring 3 with `iretq`. The user pages at
32-36 MiB are marked user-accessible while kernel pages remain supervisor-only.
An `int 0x80` boundary currently provides synchronous `read`, `write`, `exec`,
`exit`, `getcwd`, `chdir`, and directory-list operations. Standard input and
output are backed by QEMU's COM1 serial console.
The shell synchronously executes the separate `ls.elf` and `cd.elf` images.
Only one user context runs at a time: while a command is active, the kernel
keeps the shell register frame and restores it when the command calls `exit`.
`exit`, `getcwd`, `chdir`, `time`, and directory-list operations. Standard
input and output are backed by QEMU's COM1 serial console. Syscall numbers are
shared by the kernel and userspace through `typephp_os_syscall.h`.
The shell synchronously executes separate `ls.elf`, `cd.elf`, `pwd.elf`, and
`date.elf` images. Short-lived commands reuse one ELF load address; only the
resident shell has a separate image and stack. Only one user context runs at a
time: while a command is active, the kernel keeps the shell register frame and
restores it when the command calls `exit`.
Because this is a deliberately single-task model, the working directory is a
session-global property; a successful `cd` therefore remains visible after
control returns to the shell.
@ -153,7 +157,10 @@ Available commands are:
```text
ls
date
pwd
cd DOCS
pwd
ls
cd ..
```

@ -43,8 +43,9 @@ behavior.
nested directories and long filenames are next.
6. **Single-task userspace — first slice complete.** ELF64 validation/loading,
supervisor/user page separation, GDT/TSS, Ring-3 entry, synchronous
`int 0x80` system calls, COM1 standard I/O, saved parent context, and
independent freestanding C `sh`, `ls`, and `cd` programs.
`int 0x80` system calls, COM1 standard I/O, saved parent context, shared
syscall definitions, reusable command address space, and independent
freestanding C `sh`, `ls`, `cd`, `pwd`, and `date` programs.
7. **Native Class memory.** Exercise Wren GC through Zend MM and verify tracing
of PHPX fields under sustained allocation.
8. **Kernel services.** Interrupt-driven timer, keyboard, physical-page

@ -0,0 +1,18 @@
#ifndef TYPEPHP_OS_SYSCALL_H
#define TYPEPHP_OS_SYSCALL_H
/* Keep familiar Linux x86_64 numbers where the operation has a close match.
* READDIR is currently a compact TypePHP-OS directory-list operation rather
* than Linux getdents64's binary record ABI. */
enum typephp_os_syscall_number {
TYPEPHP_SYS_READ = 0,
TYPEPHP_SYS_WRITE = 1,
TYPEPHP_SYS_EXEC = 59,
TYPEPHP_SYS_EXIT = 60,
TYPEPHP_SYS_GETCWD = 79,
TYPEPHP_SYS_CHDIR = 80,
TYPEPHP_SYS_TIME = 201,
TYPEPHP_SYS_READDIR = 217,
};
#endif

@ -8,6 +8,7 @@
*/
#include "typephp_os_abi.h"
#include "typephp_os_syscall.h"
#include <stddef.h>
#include <stdint.h>
@ -22,13 +23,6 @@ enum {
KERNEL_CODE_SELECTOR = 0x08,
TSS_SELECTOR = 0x28,
IDT_SYSCALL = 0x80,
SYS_READ = 0,
SYS_WRITE = 1,
SYS_EXEC = 59,
SYS_EXIT = 60,
SYS_GETCWD = 79,
SYS_CHDIR = 80,
SYS_READDIR = 217,
};
enum {
@ -115,6 +109,31 @@ typedef struct {
uint64_t ss;
} syscall_frame;
typedef struct {
uint64_t rax;
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rbp;
uint64_t rdi;
uint64_t rsi;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t vector;
uint64_t error;
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} exception_frame;
typedef struct {
uint64_t pid;
int running;
@ -129,8 +148,24 @@ extern const unsigned char typephp_user_ls_elf_start[];
extern const unsigned char typephp_user_ls_elf_end[];
extern const unsigned char typephp_user_cd_elf_start[];
extern const unsigned char typephp_user_cd_elf_end[];
extern const unsigned char typephp_user_date_elf_start[];
extern const unsigned char typephp_user_date_elf_end[];
extern const unsigned char typephp_user_pwd_elf_start[];
extern const unsigned char typephp_user_pwd_elf_end[];
extern const unsigned char typephp_user_fault_elf_start[];
extern const unsigned char typephp_user_fault_elf_end[];
extern void typephp_os_syscall_entry(void);
extern void typephp_os_enter_user(uint64_t entry, uint64_t stack);
extern long typephp_os_time_seconds(void);
extern void typephp_os_exception_0(void);
extern void typephp_os_exception_3(void);
extern void typephp_os_exception_5(void);
extern void typephp_os_exception_6(void);
extern void typephp_os_exception_10(void);
extern void typephp_os_exception_11(void);
extern void typephp_os_exception_12(void);
extern void typephp_os_exception_13(void);
extern void typephp_os_exception_14(void);
static uint64_t gdt[7] __attribute__((aligned(16)));
static idt_gate idt[256] __attribute__((aligned(16)));
@ -176,10 +211,19 @@ static void install_tss_descriptor(uint64_t base, uint32_t limit)
gdt[6] = base >> 32u;
}
static void install_idt_gate(unsigned int vector, void (*entry)(void), uint8_t attributes)
{
uintptr_t handler = (uintptr_t) entry;
idt[vector].offset_low = handler & 0xffffu;
idt[vector].selector = KERNEL_CODE_SELECTOR;
idt[vector].attributes = attributes;
idt[vector].offset_middle = (handler >> 16u) & 0xffffu;
idt[vector].offset_high = handler >> 32u;
}
static void install_descriptor_tables(void)
{
descriptor_pointer pointer;
uintptr_t handler = (uintptr_t) typephp_os_syscall_entry;
memset(gdt, 0, sizeof(gdt));
gdt[1] = UINT64_C(0x00af9a000000ffff);
@ -205,11 +249,16 @@ static void install_descriptor_tables(void)
: "rax", "memory");
memset(idt, 0, sizeof(idt));
idt[IDT_SYSCALL].offset_low = handler & 0xffffu;
idt[IDT_SYSCALL].selector = KERNEL_CODE_SELECTOR;
idt[IDT_SYSCALL].attributes = 0xee; /* present, DPL 3, interrupt gate */
idt[IDT_SYSCALL].offset_middle = (handler >> 16u) & 0xffffu;
idt[IDT_SYSCALL].offset_high = handler >> 32u;
install_idt_gate(0, typephp_os_exception_0, 0x8e);
install_idt_gate(3, typephp_os_exception_3, 0xee);
install_idt_gate(5, typephp_os_exception_5, 0x8e);
install_idt_gate(6, typephp_os_exception_6, 0x8e);
install_idt_gate(10, typephp_os_exception_10, 0x8e);
install_idt_gate(11, typephp_os_exception_11, 0x8e);
install_idt_gate(12, typephp_os_exception_12, 0x8e);
install_idt_gate(13, typephp_os_exception_13, 0x8e);
install_idt_gate(14, typephp_os_exception_14, 0x8e);
install_idt_gate(IDT_SYSCALL, typephp_os_syscall_entry, 0xee);
pointer.limit = sizeof(idt) - 1u;
pointer.base = (uint64_t) (uintptr_t) idt;
__asm__ volatile("lidt %0" : : "m"(pointer) : "memory");
@ -272,6 +321,21 @@ static int command_image(
*image_end = typephp_user_cd_elf_end;
return 1;
}
if (strcmp(name, "date") == 0) {
*image = typephp_user_date_elf_start;
*image_end = typephp_user_date_elf_end;
return 1;
}
if (strcmp(name, "pwd") == 0) {
*image = typephp_user_pwd_elf_start;
*image_end = typephp_user_pwd_elf_end;
return 1;
}
if (strcmp(name, "fault") == 0) {
*image = typephp_user_fault_elf_start;
*image_end = typephp_user_fault_elf_end;
return 1;
}
return 0;
}
@ -380,31 +444,121 @@ static long syscall_exit(syscall_frame *frame, long status)
return status;
}
static void write_unsigned(uint64_t value)
{
char digits[20];
size_t count = 0;
do {
digits[count++] = (char) ('0' + value % 10u);
value /= 10u;
} while (value != 0);
while (count != 0) {
--count;
typephp_os_write(&digits[count], 1);
}
}
static void write_hex(uint64_t value)
{
static const char digits[] = "0123456789abcdef";
char output[18];
int index;
output[0] = '0';
output[1] = 'x';
for (index = 0; index < 16; ++index) {
output[index + 2] = digits[(value >> ((15 - index) * 4)) & 0x0fu];
}
typephp_os_write(output, sizeof(output));
}
static const char *exception_name(uint64_t vector)
{
switch (vector) {
case 0: return "divide error";
case 3: return "breakpoint";
case 5: return "bounds";
case 6: return "invalid opcode";
case 10: return "invalid TSS";
case 11: return "segment not present";
case 12: return "stack fault";
case 13: return "general protection";
case 14: return "page fault";
default: return "unknown";
}
}
static void restore_shell_after_fault(exception_frame *frame)
{
syscall_frame *parent = &foreground_process.parent_frame;
/* The general-register prefixes of both frame formats are identical. */
memcpy(frame, parent, offsetof(syscall_frame, rip));
frame->rax = (uint64_t) -1;
frame->rip = parent->rip;
frame->cs = parent->cs;
frame->rflags = parent->rflags;
frame->rsp = parent->rsp;
frame->ss = parent->ss;
foreground_process.parent_waiting = 0;
foreground_process.pid = 1;
}
void typephp_os_exception_dispatch(exception_frame *frame)
{
uint64_t fault_address = 0;
if (frame->vector == 14) {
__asm__ volatile("mov %%cr2, %0" : "=r"(fault_address));
}
typephp_os_write("User process ", sizeof("User process ") - 1);
write_unsigned(foreground_process.pid);
typephp_os_write(" fault: ", sizeof(" fault: ") - 1);
typephp_os_write(exception_name(frame->vector), strlen(exception_name(frame->vector)));
typephp_os_write(" (#", sizeof(" (#") - 1);
write_unsigned(frame->vector);
typephp_os_write(") at ", sizeof(") at ") - 1);
write_hex(frame->rip);
if (frame->vector == 14) {
typephp_os_write(", address ", sizeof(", address ") - 1);
write_hex(fault_address);
}
typephp_os_write("\n", 1);
if ((frame->cs & 3u) != 3u) {
panic("kernel-mode exception\n");
}
if (!foreground_process.parent_waiting) {
panic("resident shell faulted\n");
}
restore_shell_after_fault(frame);
}
long typephp_os_syscall_dispatch(syscall_frame *frame)
{
switch (frame->rax) {
case SYS_READ:
case TYPEPHP_SYS_READ:
if (frame->rdi != 0 || !user_buffer((void *) frame->rsi, frame->rdx)) {
return -1;
}
return typephp_os_console_read((void *) frame->rsi, frame->rdx);
case SYS_WRITE:
case TYPEPHP_SYS_WRITE:
if ((frame->rdi != 1 && frame->rdi != 2)
|| !user_buffer((void *) frame->rsi, frame->rdx)) {
return -1;
}
typephp_os_write((const char *) frame->rsi, frame->rdx);
return (long) frame->rdx;
case SYS_EXEC:
case TYPEPHP_SYS_EXEC:
return syscall_exec(frame, (const char *) frame->rdi, (const char *) frame->rsi);
case SYS_GETCWD:
case TYPEPHP_SYS_GETCWD:
return syscall_getcwd((char *) frame->rdi, frame->rsi);
case SYS_CHDIR:
case TYPEPHP_SYS_CHDIR:
return syscall_chdir((const char *) frame->rdi);
case SYS_READDIR:
case TYPEPHP_SYS_TIME:
return typephp_os_time_seconds();
case TYPEPHP_SYS_READDIR:
return syscall_readdir((const char *) frame->rdi,
(char *) frame->rsi, frame->rdx);
case SYS_EXIT:
case TYPEPHP_SYS_EXIT:
return syscall_exit(frame, (long) frame->rdi);
default:
return -1;

@ -20,6 +20,9 @@ objects:
- build/objects/sh-image.o
- build/objects/ls-image.o
- build/objects/cd-image.o
- build/objects/date-image.o
- build/objects/pwd-image.o
- build/objects/fault-image.o
build-dir: build/generated
output: build/kernel64.elf
cxx-std: c++17

@ -1,13 +1,5 @@
<?php
final class KernelGreeting
{
public function render(string $now): string
{
return $now . ' Hello TypePHP-OS!';
}
}
function writeLine(string $text, int $color): void
{
kernel_write($text, $color);
@ -176,7 +168,5 @@ function main(): void
runMathSelfCheck();
runFilesystemSelfCheck();
runPrimeDemo(100);
$greeting = new KernelGreeting();
echo $greeting->render(date('Y-m-d H:i:s')), "\n";
kernel_process_start();
}

@ -16,7 +16,7 @@ if timeout 8 qemu-system-x86_64 \
-no-shutdown \
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
>"${log}" 2>&1 \
<<< $'\nls\ncd DOCS\nls\ncd ..\nls\n'; then
<<< $'\ndate\npwd\nls\ncd DOCS\npwd\nls\ncd ..\nls\n'; then
status=0
else
status=$?
@ -42,11 +42,13 @@ grep -q "PHP directory scan: ., .., DATA, DOCS, HELLO.TXT, STREAM.TXT" "${log}"
grep -q "Calculate primes: 0-100" "${log}"
grep -q "Prime count: 25" "${log}"
grep -q "Prime list: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97" "${log}"
grep -Eq '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} Hello TypePHP-OS![[:space:]]*$' "${log}"
grep -q "Process 1: sh.elf (Ring 3)" "${log}"
grep -q "TypePHP-OS user shell" "${log}"
grep -q "Ring 3 confirmed" "${log}"
grep -q "Commands: ls, cd <directory>, pwd, date" "${log}"
grep -Eq '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} UTC' "${log}"
grep -Fq 'typephp-os:/$ ' "${log}"
grep -Fq 'typephp-os:/DOCS$ ' "${log}"
grep -q '^/DOCS' "${log}"
grep -q '^HELLO.TXT' "${log}"
cat "${log}"

@ -0,0 +1,82 @@
#include "syscall.h"
static int leap_year(long year)
{
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
static void append_two_digits(char *output, size_t *offset, long value)
{
output[(*offset)++] = (char) ('0' + (value / 10) % 10);
output[(*offset)++] = (char) ('0' + value % 10);
}
static void append_four_digits(char *output, size_t *offset, long value)
{
output[(*offset)++] = (char) ('0' + (value / 1000) % 10);
output[(*offset)++] = (char) ('0' + (value / 100) % 10);
output[(*offset)++] = (char) ('0' + (value / 10) % 10);
output[(*offset)++] = (char) ('0' + value % 10);
}
void _start(const char *argument)
{
static const int month_days[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
};
char output[25];
size_t offset = 0;
long seconds = typephp_syscall(TYPEPHP_SYS_TIME, 0, 0, 0);
long days;
long day_seconds;
long year = 1970;
long month = 0;
int days_in_year;
int days_in_month;
(void) argument;
if (seconds < 0) {
typephp_write("date: clock unavailable\n");
typephp_exit(1);
}
days = seconds / 86400;
day_seconds = seconds % 86400;
for (;;) {
days_in_year = leap_year(year) ? 366 : 365;
if (days < days_in_year) {
break;
}
days -= days_in_year;
++year;
}
for (;;) {
days_in_month = month_days[month];
if (month == 1 && leap_year(year)) {
++days_in_month;
}
if (days < days_in_month) {
break;
}
days -= days_in_month;
++month;
}
append_four_digits(output, &offset, year);
output[offset++] = '-';
append_two_digits(output, &offset, month + 1);
output[offset++] = '-';
append_two_digits(output, &offset, days + 1);
output[offset++] = ' ';
append_two_digits(output, &offset, day_seconds / 3600);
output[offset++] = ':';
append_two_digits(output, &offset, (day_seconds / 60) % 60);
output[offset++] = ':';
append_two_digits(output, &offset, day_seconds % 60);
output[offset++] = ' ';
output[offset++] = 'U';
output[offset++] = 'T';
output[offset++] = 'C';
output[offset++] = '\n';
typephp_write_bytes(output, offset);
typephp_exit(0);
}

@ -0,0 +1,14 @@
#include "syscall.h"
void _start(const char *argument)
{
char cwd[16];
(void) argument;
if (typephp_syscall(TYPEPHP_SYS_GETCWD, (long) cwd, sizeof(cwd), 0) < 0) {
typephp_write("pwd: working directory unavailable\n");
typephp_exit(1);
}
typephp_write(cwd);
typephp_write("\n");
typephp_exit(0);
}

@ -61,7 +61,7 @@ void _start(void)
}
typephp_write("TypePHP-OS user shell\n");
typephp_write("Ring 3 confirmed\n");
typephp_write("Commands: ls, cd <directory>\n");
typephp_write("Commands: ls, cd <directory>, pwd, date, fault\n");
for (;;) {
char *argument;
show_prompt();
@ -78,7 +78,9 @@ void _start(void)
++argument;
}
}
if (string_equal(line, "ls") || string_equal(line, "cd")) {
if (string_equal(line, "ls") || string_equal(line, "cd")
|| string_equal(line, "pwd") || string_equal(line, "date")
|| string_equal(line, "fault")) {
if (typephp_syscall(TYPEPHP_SYS_EXEC,
(long) line, (long) argument, 0) < 0) {
typephp_write("sh: unable to execute command\n");

@ -1,17 +1,9 @@
#ifndef TYPEPHP_OS_USER_SYSCALL_H
#define TYPEPHP_OS_USER_SYSCALL_H
typedef unsigned long size_t;
#include <typephp_os_syscall.h>
enum {
TYPEPHP_SYS_READ = 0,
TYPEPHP_SYS_WRITE = 1,
TYPEPHP_SYS_EXEC = 59,
TYPEPHP_SYS_EXIT = 60,
TYPEPHP_SYS_GETCWD = 79,
TYPEPHP_SYS_CHDIR = 80,
TYPEPHP_SYS_READDIR = 217,
};
typedef unsigned long size_t;
static inline long typephp_syscall(
long number, long first, long second, long third)

Loading…
Cancel
Save