From 875c7268108417f843515f724f6acfcb9de7b3cf Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 11 Sep 2026 18:29:28 +0800 Subject: [PATCH] feat(kernel): add memory information system call and free command - Add typephp_os_disk_cache_bytes function to return ATA cache size - Implement C++ terminate function with typephp_os_panic call - Create new free.cc with php_os_memory_value native function - Add free.php memory reporting command with pool accounting - Define free.yml build configuration for the new command - Update hello.yml with additional compiler flags - Add syscall declaration to ioctl.c - Introduce arena_begin variable and typephp_os_memory_total function - Implement vfprintf function using vprintf - Add typephp_os_longjmp implementation with proper asm annotation - Update fprintf to use v --- examples/typephp-os/Makefile | 44 +++++++++--- examples/typephp-os/README.md | 16 +++++ examples/typephp-os/ROADMAP.md | 9 +++ examples/typephp-os/kernel/core/abi/cxx.cpp | 5 ++ examples/typephp-os/kernel/core/abi/libc.c | 32 +++++++-- .../kernel/core/abi/typephp_os_abi.h | 1 + .../kernel/core/abi/typephp_os_memory.h | 24 +++++++ .../kernel/core/abi/typephp_os_syscall.h | 1 + examples/typephp-os/kernel/core/ata.c | 5 ++ examples/typephp-os/kernel/core/memory.c | 20 +++++- examples/typephp-os/kernel/core/process.c | 24 +++++++ examples/typephp-os/project.yml | 6 ++ examples/typephp-os/tools/test-qemu.sh | 9 ++- examples/typephp-os/user/README.md | 6 ++ examples/typephp-os/user/cmd/sh.c | 4 +- .../typephp-os/user/include/sys/syscall.h | 1 + examples/typephp-os/user/nano/free.cc | 20 ++++++ examples/typephp-os/user/nano/free.php | 49 ++++++++++++++ examples/typephp-os/user/nano/free.yml | 67 +++++++++++++++++++ examples/typephp-os/user/nano/hello.yml | 6 ++ examples/typephp-os/user/nano/memory.stub.php | 5 ++ examples/typephp-os/user/runtime/ioctl.c | 2 + examples/typephp-os/user/runtime/memory.c | 9 +++ 23 files changed, 345 insertions(+), 20 deletions(-) create mode 100644 examples/typephp-os/kernel/core/abi/typephp_os_memory.h create mode 100644 examples/typephp-os/user/nano/free.cc create mode 100644 examples/typephp-os/user/nano/free.php create mode 100644 examples/typephp-os/user/nano/free.yml create mode 100644 examples/typephp-os/user/nano/memory.stub.php create mode 100644 examples/typephp-os/user/runtime/memory.c diff --git a/examples/typephp-os/Makefile b/examples/typephp-os/Makefile index 7cfb635f..eab5b2ac 100644 --- a/examples/typephp-os/Makefile +++ b/examples/typephp-os/Makefile @@ -12,6 +12,7 @@ USER_PROGRAMS := sh $(USER_COMMANDS) USER_SH_ELF := $(BUILD)/sh.elf USER_COMMAND_ELFS := $(addprefix $(BUILD)/,$(addsuffix .elf,$(USER_COMMANDS))) NANO_USER_ELF := $(BUILD)/tnhello.elf +TYPEPHP_FREE_ELF := $(BUILD)/free.elf TYPEPHP_OS_LIBRARY := $(BUILD)/libtypephp-os.a TYPEPHP_OS_LIBRARY_OBJECT_DIR := $(BUILD)/libtypephp-os COMPILER_RT_LIBRARY := $(BUILD)/libcompiler-rt-builtins.a @@ -23,7 +24,7 @@ COMPILER_RT_SOURCES := $(shell awk '$$2 ~ /\.c$$/ { print "thirdparty/compiler-r COMPILER_RT_OBJECTS := $(patsubst thirdparty/compiler-rt/lib/builtins/%.c,$(COMPILER_RT_OBJECT_DIR)/%.o,$(COMPILER_RT_SOURCES)) TYPEPHP_OS_LIBRARY_C_SOURCES := user/runtime/posix.c user/runtime/dirent.c \ user/runtime/fcntl.c user/runtime/ioctl.c kernel/core/abi/error.c kernel/core/abi/string.c \ - kernel/core/abi/libc.c $(OPENLIBM_SOURCES) + user/runtime/memory.c kernel/core/abi/libc.c $(OPENLIBM_SOURCES) TYPEPHP_OS_LIBRARY_CXX_SOURCES := user/runtime/host.cc kernel/core/abi/cxx.cpp TYPEPHP_OS_LIBRARY_ASM_SOURCES := user/runtime/crt0.S user/runtime/syscall.S \ kernel/core/abi/unimplemented.S @@ -35,12 +36,15 @@ TYPEPHP_OS_LIBRARY_OBJECTS := \ TYPEPHP_OS_LIBRARY_DEPFILES := $(addsuffix .d,$(TYPEPHP_OS_LIBRARY_OBJECTS)) NANO_USER_SOURCES := user/nano/hello.php user/nano/hello.yml user/runtime/linker.ld \ $(TYPEPHP_OS_LIBRARY) $(COMPILER_RT_LIBRARY) +TYPEPHP_FREE_SOURCES := user/nano/free.php user/nano/memory.stub.php \ + user/nano/free.cc user/nano/free.yml user/runtime/linker.ld \ + $(TYPEPHP_OS_LIBRARY) $(COMPILER_RT_LIBRARY) -BOOTFLAGS := -m32 -O2 -ffreestanding -fno-pic -fno-pie \ +BOOTFLAGS := -m32 -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -ffreestanding -fno-pic -fno-pie \ -fno-stack-protector -Wall -Wextra -KERNEL64_BOOTFLAGS := -m64 -O2 -ffreestanding -fno-builtin -fno-pic -fno-pie \ +KERNEL64_BOOTFLAGS := -m64 -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -ffreestanding -fno-builtin -fno-pic -fno-pie \ -fno-stack-protector -mno-red-zone -mcmodel=small -Wall -Wextra -USER_CFLAGS := -m64 -O2 -ffreestanding -fno-builtin -fno-pic -fno-pie \ +USER_CFLAGS := -m64 -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -ffreestanding -fno-builtin -fno-pic -fno-pie \ -fno-stack-protector -mno-red-zone -Wall -Wextra -Iuser/include -Ikernel/core/abi USER_HEADERS := $(shell find user/include -type f) USER_LDFLAGS := -m elf_x86_64 -nostdlib -static --undefined=_start \ @@ -56,11 +60,13 @@ TYPEPHP_OS_RUNTIME_INCLUDES := -Ikernel/core/abi \ -I$(PHP_NANO_DIR)/include -I$(PHP_NANO_DIR)/main -I$(PHP_NANO_DIR)/TSRM \ -I$(PHP_NANO_DIR)/ext/date/lib -I$(PHP_NANO_DIR)/ext/pcre/pcre2lib \ -I$(PHPX_DIR)/include -I$(PHPX_DIR)/thirdparty/wren-gc/include -TYPEPHP_OS_RUNTIME_CFLAGS := -m64 -O0 -std=c11 -ffreestanding -fno-builtin \ +TYPEPHP_OS_RUNTIME_CFLAGS := -m64 -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \ + -std=c11 -ffreestanding -fno-builtin \ -fno-pic -fno-pie -fno-stack-protector -mno-red-zone -mcmodel=small \ -ffunction-sections -fdata-sections -Wall -Wextra \ $(TYPEPHP_OS_RUNTIME_DEFINES) $(TYPEPHP_OS_RUNTIME_INCLUDES) -TYPEPHP_OS_RUNTIME_CXXFLAGS := -m64 -O0 -std=c++17 -ffreestanding -fno-builtin \ +TYPEPHP_OS_RUNTIME_CXXFLAGS := -m64 -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \ + -std=c++17 -ffreestanding -fno-builtin \ -fno-pic -fno-pie -fno-stack-protector -mno-red-zone -mcmodel=small \ -fno-rtti -fno-threadsafe-statics -ffunction-sections -fdata-sections \ -Wall -Wextra \ @@ -69,6 +75,15 @@ TYPEPHP_OS_RUNTIME_ASMFLAGS := -m64 -ffreestanding -fno-pic -fno-pie \ -fno-stack-protector -mno-red-zone -mcmodel=small ARFLAGS := rcs +# Keep symbol information on the host while installing only compact runtime +# ELF files into the FAT16 image. GDB can discover the adjacent .debug file +# through the GNU debug link retained in the stripped executable. +define STRIP_ELF + objcopy --only-keep-debug $(1) $(1).debug + strip --strip-all $(1) + objcopy --add-gnu-debuglink=$(1).debug $(1) +endef + .PHONY: all thirdparty thirdparty-smoke compiler-rt-builtins payload objects user-runtime nano-user disk run test clean all: $(KERNEL) $(DISK) @@ -83,6 +98,7 @@ compiler-rt-builtins: $(COMPILER_RT_LIBRARY) payload: thirdparty objects $(COMPILER_RT_LIBRARY) cd ../.. && ./bin/tpc.php --nano examples/typephp-os/project.yml + $(call STRIP_ELF,$(PAYLOAD_ELF)) # Startup sources are built explicitly by Make. The 64-bit entry object is # injected into tpc's final link through project.yml; the 32-bit Multiboot @@ -91,11 +107,11 @@ objects: $(BOOTSTRAP_OBJECT) $(KERNEL64_ENTRY_OBJECT) user-runtime: $(TYPEPHP_OS_LIBRARY) -nano-user: $(TYPEPHP_OS_LIBRARY) $(NANO_USER_ELF) +nano-user: $(TYPEPHP_OS_LIBRARY) $(NANO_USER_ELF) $(TYPEPHP_FREE_ELF) disk: $(DISK) -$(DISK): $(USER_SH_ELF) $(USER_COMMAND_ELFS) $(NANO_USER_ELF) | $(BUILD) +$(DISK): $(USER_SH_ELF) $(USER_COMMAND_ELFS) $(NANO_USER_ELF) $(TYPEPHP_FREE_ELF) | $(BUILD) truncate -s 32M $@ mkfs.fat -F 16 -n TYPEPHPOS $@ mmd -i $@ ::/BIN @@ -103,6 +119,7 @@ $(DISK): $(USER_SH_ELF) $(USER_COMMAND_ELFS) $(NANO_USER_ELF) | $(BUILD) mcopy -o -i $@ $(BUILD)/$$program.elf ::/BIN/$$program.elf; \ done mcopy -o -i $@ $(NANO_USER_ELF) ::/BIN/TNHELLO.ELF + mcopy -o -i $@ $(TYPEPHP_FREE_ELF) ::/BIN/FREE.ELF $(BUILD): mkdir -p $@ @@ -151,14 +168,21 @@ $(TYPEPHP_OS_LIBRARY): $(TYPEPHP_OS_LIBRARY_OBJECTS) | $(BUILD) $(NANO_USER_ELF): $(NANO_USER_SOURCES) | thirdparty $(BUILD) cd ../.. && ./bin/tpc.php --nano examples/typephp-os/user/nano/hello.yml + $(call STRIP_ELF,$@) + +$(TYPEPHP_FREE_ELF): $(TYPEPHP_FREE_SOURCES) | thirdparty $(BUILD) + cd ../.. && ./bin/tpc.php --nano examples/typephp-os/user/nano/free.yml + $(call STRIP_ELF,$@) $(USER_SH_ELF): $(OBJECT_DIR)/sh.o $(TYPEPHP_OS_LIBRARY) $(COMPILER_RT_LIBRARY) user/runtime/linker.ld Makefile | $(BUILD) ld $(USER_LDFLAGS) --defsym USER_BASE=0x40000000 -o $@ \ $(OBJECT_DIR)/sh.o $(TYPEPHP_OS_LIBRARY) $(COMPILER_RT_LIBRARY) + $(call STRIP_ELF,$@) $(USER_COMMAND_ELFS): $(BUILD)/%.elf: $(OBJECT_DIR)/%.o $(TYPEPHP_OS_LIBRARY) $(COMPILER_RT_LIBRARY) user/runtime/linker.ld Makefile | $(BUILD) ld $(USER_LDFLAGS) --defsym USER_BASE=0x41000000 -o $@ \ $(OBJECT_DIR)/$*.o $(TYPEPHP_OS_LIBRARY) $(COMPILER_RT_LIBRARY) + $(call STRIP_ELF,$@) $(KERNEL): payload objcopy -O binary $(PAYLOAD_ELF) $(PAYLOAD_BIN) @@ -167,13 +191,14 @@ $(KERNEL): payload $(PAYLOAD_BIN) $(PAYLOAD_OBJECT) ld -m elf_i386 -T boot/linker.ld -o $@ \ $(BOOTSTRAP_OBJECT) $(PAYLOAD_OBJECT) + $(call STRIP_ELF,$@) run: all qemu-system-x86_64 -m 512M -kernel $(KERNEL) \ -drive file=$(DISK),format=raw,if=ide,index=0 \ -display none -serial stdio -monitor none -no-reboot -no-shutdown -test: $(KERNEL) $(USER_SH_ELF) $(USER_COMMAND_ELFS) $(NANO_USER_ELF) +test: $(KERNEL) $(USER_SH_ELF) $(USER_COMMAND_ELFS) $(NANO_USER_ELF) $(TYPEPHP_FREE_ELF) truncate -s 32M $(DISK) mkfs.fat -F 16 -n TYPEPHPOS $(DISK) mmd -i $(DISK) ::/BIN @@ -181,6 +206,7 @@ test: $(KERNEL) $(USER_SH_ELF) $(USER_COMMAND_ELFS) $(NANO_USER_ELF) mcopy -o -i $(DISK) $(BUILD)/$$program.elf ::/BIN/$$program.elf; \ done mcopy -o -i $(DISK) $(NANO_USER_ELF) ::/BIN/TNHELLO.ELF + mcopy -o -i $(DISK) $(TYPEPHP_FREE_ELF) ::/BIN/FREE.ELF # An alias not known while linking the kernel verifies disk-based discovery. mcopy -o -i $(DISK) $(BUILD)/echo.elf ::/BIN/hello.elf mcopy -o -i $(DISK) tools/invalid-elf.txt ::/BIN/bad.elf diff --git a/examples/typephp-os/README.md b/examples/typephp-os/README.md index a9f2519f..26c2f37c 100644 --- a/examples/typephp-os/README.md +++ b/examples/typephp-os/README.md @@ -87,6 +87,9 @@ The build produces these useful files: linked with the shared TypePHP-OS runtime rather than a hosted libc. - `build/tnhello.elf`: a full TypePHP + PHPX + PHP Nano Ring-3 executable generated by tpc from `user/nano/hello.php`. +- `build/free.elf`: the tpc-generated TypePHP memory-reporting command. +- matching `build/*.elf.debug` files: host-side symbols removed from runtime + ELF files; keep these beside the binaries when debugging with GDB. - `build/libtypephp-os.a`: the sole reusable userspace platform archive linked by both C programs and every tpc-generated TypePHP program. Static archive member selection keeps small C commands from pulling in the PHP Nano host. @@ -165,6 +168,9 @@ The QEMU smoke test currently verifies: - a TypePHP prime calculation for 0–100; - disk-backed ELF64 loading, Linux-style `argc/argv` startup, and libc-shaped userspace calls, including a complete PHP Nano program generated by tpc; +- an independently compiled TypePHP `free` command reporting usable RAM, + kernel Zend-arena usage, physical-page usage, the kernel reservation, and + block-cache storage through a small private memory-information ABI; - a separate x86-64 address space for the resident shell and every command, 4 KiB user mappings, a guarded 64 KiB stack, NX/WP enforcement, and ELF `RX`/`RW` segment permissions; @@ -236,6 +242,16 @@ userspace compatibility rules are recorded in [`user/README.md`](user/README.md) the long-term target is GCC/glibc-compatible userspace, and Linux syscall numbers are reserved for genuinely compatible semantics. +The kernel, PHP Nano/PHPX sources, shared userspace runtime, bootstrap, and +small C commands are release-built with `-O2`. Because the host compiler may +enable glibc fortification by default, freestanding builds explicitly disable +`_FORTIFY_SOURCE`; TypePHP-OS supplies and audits its own libc/POSIX boundary. +Runtime ELF files are stripped before installation into FAT16, while adjacent +`.debug` files retain their host-side symbols for GDB. Hardware access, CPU +context entry, and the syscall trampoline remain C or assembly. Filesystem +policy, FAT16, startup checks, demonstrations, and the `free` command's +calculations and presentation are implemented in TypePHP. + The shell synchronously executes separate command ELF files from FAT16. Entering `name` requests `/BIN/.ELF`; the kernel validates the ELF header, program table, file bounds, target address range, and entry point before diff --git a/examples/typephp-os/ROADMAP.md b/examples/typephp-os/ROADMAP.md index 34e9977e..eb59011e 100644 --- a/examples/typephp-os/ROADMAP.md +++ b/examples/typephp-os/ROADMAP.md @@ -90,6 +90,9 @@ behavior. Unavailable ABI functions remain explicit panic stubs. Fixed-console `ioctl(TIOCGWINSZ)` reports the VGA dimensions while other terminal requests return `ENOTTY`; a complete termios subsystem is not implied. + A private memory-information snapshot now supports a tpc-built TypePHP + `free` command with kernel Zend-arena, page-pool, reservation, and block-cache + accounting. Release builds use `-O2` across the kernel and userspace. Selected upstream LLVM compiler-rt builtins now provide 128-bit integer helper symbols. A five-applet Toybox build is pinned as a porting probe but does not yet replace the working userspace commands. @@ -108,3 +111,9 @@ behavior. Later architectures may provide different bootstraps and host ABI adapters. Generated TypePHP code and PHPX values remain 64-bit on every target. + +Pure policy and data-processing work should continue moving to TypePHP. C is +kept for php-src reuse and narrow ABI/hardware adapters; assembly is kept only +where the CPU contract requires it. Suitable next migrations include shell +tokenization/dispatch and higher-level VFS/page-cache policy after the required +stream and console primitives are exposed to TypePHP userspace. diff --git a/examples/typephp-os/kernel/core/abi/cxx.cpp b/examples/typephp-os/kernel/core/abi/cxx.cpp index 9cd56b3d..aa67a114 100644 --- a/examples/typephp-os/kernel/core/abi/cxx.cpp +++ b/examples/typephp-os/kernel/core/abi/cxx.cpp @@ -185,6 +185,11 @@ namespace std { const nothrow_t nothrow{}; +[[noreturn]] void terminate() noexcept +{ + typephp_os_panic("C++ termination"); +} + [[noreturn]] void __throw_length_error(const char *) { typephp_os_panic("C++ container length error"); diff --git a/examples/typephp-os/kernel/core/abi/libc.c b/examples/typephp-os/kernel/core/abi/libc.c index d8e61842..9fb52bf1 100644 --- a/examples/typephp-os/kernel/core/abi/libc.c +++ b/examples/typephp-os/kernel/core/abi/libc.c @@ -35,6 +35,7 @@ typedef struct typephp_os_aligned_block { enum { TYPEPHP_OS_ALIGNED_BLOCK_CAPACITY = 64 }; static uintptr_t arena_cursor; +static uintptr_t arena_begin; static uintptr_t arena_end; static typephp_os_aligned_block aligned_blocks[TYPEPHP_OS_ALIGNED_BLOCK_CAPACITY]; @@ -95,14 +96,21 @@ void typephp_os_memory_init(void *address, size_t size) aligned_blocks[index].allocated = 0; } if (size > UINTPTR_MAX - begin) { + arena_begin = 0; arena_cursor = 0; arena_end = 0; return; } + arena_begin = begin; arena_cursor = begin; arena_end = begin + size; } +size_t typephp_os_memory_total(void) +{ + return arena_end >= arena_begin ? (size_t) (arena_end - arena_begin) : 0; +} + size_t typephp_os_memory_available(void) { return arena_end >= arena_cursor ? (size_t) (arena_end - arena_cursor) : 0; @@ -594,6 +602,12 @@ int vprintf(const char *format, va_list args) return written; } +int vfprintf(void *stream, const char *format, va_list args) +{ + (void) stream; + return vprintf(format, args); +} + int printf(const char *format, ...) { va_list args; @@ -653,7 +667,13 @@ __attribute__((noreturn)) void __longjmp_chk(void *environment, int value) typephp_os_panic("zend_bailout"); } -__attribute__((noreturn)) void longjmp(jmp_buf environment, int value) +/* glibc's fortified setjmp header gives the longjmp C identifier an + * __longjmp_chk assembler name at -O2. Use a private C identifier so the + * freestanding runtime can intentionally provide both public ABI symbols. */ +__attribute__((noreturn)) void typephp_os_longjmp(jmp_buf environment, int value) + __asm__("longjmp"); + +__attribute__((noreturn)) void typephp_os_longjmp(jmp_buf environment, int value) { (void) environment; (void) value; @@ -687,11 +707,11 @@ size_t fwrite(const void *data, size_t size, size_t count, void *stream) int fprintf(void *stream, const char *format, ...) { - (void) stream; - /* Zend's allocator only uses this on fatal paths. Keep the implementation - * allocation-free; the complete formatter belongs to the standard layer. */ - typephp_os_write(format, strlen(format)); - return (int) strlen(format); + va_list args; + va_start(args, format); + const int result = vfprintf(stream, format, args); + va_end(args); + return result; } int __fprintf_chk(void *stream, int flag, const char *format, ...) diff --git a/examples/typephp-os/kernel/core/abi/typephp_os_abi.h b/examples/typephp-os/kernel/core/abi/typephp_os_abi.h index ff09297b..4e3737c6 100644 --- a/examples/typephp-os/kernel/core/abi/typephp_os_abi.h +++ b/examples/typephp-os/kernel/core/abi/typephp_os_abi.h @@ -19,6 +19,7 @@ extern "C" { /* Install the contiguous physical-memory arena used by the libc/POSIX shim. * The caller owns page-table setup and must keep the whole region mapped. */ void typephp_os_memory_init(void *address, size_t size); +size_t typephp_os_memory_total(void); size_t typephp_os_memory_available(void); /* C++17 global new/delete are supplied by TypePHP OS and allocate diff --git a/examples/typephp-os/kernel/core/abi/typephp_os_memory.h b/examples/typephp-os/kernel/core/abi/typephp_os_memory.h new file mode 100644 index 00000000..b1e5d54a --- /dev/null +++ b/examples/typephp-os/kernel/core/abi/typephp_os_memory.h @@ -0,0 +1,24 @@ +#ifndef TYPEPHP_OS_MEMORY_H +#define TYPEPHP_OS_MEMORY_H + +#include + +typedef struct { + uint64_t total_bytes; + uint64_t kernel_reserved_bytes; + uint64_t zend_total_bytes; + uint64_t zend_free_bytes; + uint64_t page_total_bytes; + uint64_t page_free_bytes; + uint64_t block_cache_bytes; +} typephp_os_memory_info; + +#ifdef __cplusplus +extern "C" { +#endif +int typephp_os_get_memory_info(typephp_os_memory_info *info); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/typephp-os/kernel/core/abi/typephp_os_syscall.h b/examples/typephp-os/kernel/core/abi/typephp_os_syscall.h index 630701f1..91e3f512 100644 --- a/examples/typephp-os/kernel/core/abi/typephp_os_syscall.h +++ b/examples/typephp-os/kernel/core/abi/typephp_os_syscall.h @@ -48,6 +48,7 @@ enum typephp_os_syscall_number { TYPEPHP_SYS_FACCESSAT = 269, TYPEPHP_SYS_SPAWN = 0x54500001, TYPEPHP_SYS_RENAME = 0x54500003, + TYPEPHP_SYS_MEMORY_INFO = 0x54500004, }; #endif diff --git a/examples/typephp-os/kernel/core/ata.c b/examples/typephp-os/kernel/core/ata.c index f68ca087..02b614d7 100644 --- a/examples/typephp-os/kernel/core/ata.c +++ b/examples/typephp-os/kernel/core/ata.c @@ -260,6 +260,11 @@ unsigned long typephp_os_disk_cache_misses(void) return (unsigned long) ata_cache_miss_count; } +unsigned long typephp_os_disk_cache_bytes(void) +{ + return (unsigned long) sizeof(ata_cache); +} + int typephp_os_disk_flush(void) { if (!ata_wait_not_busy()) { diff --git a/examples/typephp-os/kernel/core/memory.c b/examples/typephp-os/kernel/core/memory.c index 8c17e856..c98f6a1d 100644 --- a/examples/typephp-os/kernel/core/memory.c +++ b/examples/typephp-os/kernel/core/memory.c @@ -43,6 +43,7 @@ static uint64_t page_cursor; static uint64_t page_begin; static uint64_t page_end; static uint64_t free_page_head; +static uint64_t total_pages; static uint64_t available_pages; static uint64_t align_up(uint64_t value, uint64_t alignment) @@ -61,6 +62,7 @@ void physical_memory_init(uint64_t multiboot_info_address) page_begin = 0; page_end = 0; free_page_head = 0; + total_pages = 0; available_pages = 0; if ((info->flags & MULTIBOOT_INFO_MEMORY_MAP) == 0) { @@ -110,7 +112,8 @@ void physical_memory_init(uint64_t multiboot_info_address) page_begin = page_cursor; page_end = chunk_end & ~(PAGE_SIZE - 1); if (page_end > page_cursor) { - available_pages = (page_end - page_cursor) / PAGE_SIZE; + total_pages = (page_end - page_cursor) / PAGE_SIZE; + available_pages = total_pages; } } } @@ -151,6 +154,21 @@ uint64_t physical_page_available(void) return available_pages; } +uint64_t physical_page_total(void) +{ + return total_pages; +} + +uint64_t physical_memory_bytes(void) +{ + return usable_memory_bytes; +} + +uint64_t physical_kernel_reserved_bytes(void) +{ + return KERNEL_RESERVED_END; +} + uint64_t physical_memory_megabytes(void) { return usable_memory_bytes >> 20; diff --git a/examples/typephp-os/kernel/core/process.c b/examples/typephp-os/kernel/core/process.c index a58a6cc6..0cf9ec84 100644 --- a/examples/typephp-os/kernel/core/process.c +++ b/examples/typephp-os/kernel/core/process.c @@ -8,6 +8,7 @@ */ #include "typephp_os_abi.h" +#include "typephp_os_memory.h" #include "typephp_os_syscall.h" #include "vm.h" @@ -217,6 +218,10 @@ extern void typephp_os_exception_13(void); extern void typephp_os_exception_14(void); extern int rename(const char *old_path, const char *new_path); extern uint64_t physical_page_available(void); +extern uint64_t physical_page_total(void); +extern uint64_t physical_memory_bytes(void); +extern uint64_t physical_kernel_reserved_bytes(void); +extern unsigned long typephp_os_disk_cache_bytes(void); static uint64_t gdt[7] __attribute__((aligned(16))); static idt_gate idt[256] __attribute__((aligned(16))); @@ -844,6 +849,23 @@ static long syscall_ioctl(int fd, unsigned long request, void *argument) } } +static long syscall_memory_info(typephp_os_memory_info *result) +{ + typephp_os_memory_info info; + if (!user_buffer(result, sizeof(*result))) { + return -EFAULT; + } + info.total_bytes = physical_memory_bytes(); + info.kernel_reserved_bytes = physical_kernel_reserved_bytes(); + info.zend_total_bytes = typephp_os_memory_total(); + info.zend_free_bytes = typephp_os_memory_available(); + info.page_total_bytes = physical_page_total() * UINT64_C(4096); + info.page_free_bytes = physical_page_available() * UINT64_C(4096); + info.block_cache_bytes = typephp_os_disk_cache_bytes(); + memcpy(result, &info, sizeof(info)); + return 0; +} + static unsigned int vm_protection(int protection) { unsigned int flags = 0; @@ -1331,6 +1353,8 @@ long typephp_os_syscall_dispatch(syscall_frame *frame) return syscall_exit(frame, (long) frame->rdi); case TYPEPHP_SYS_UNAME: return syscall_uname((user_utsname *) frame->rdi); + case TYPEPHP_SYS_MEMORY_INFO: + return syscall_memory_info((typephp_os_memory_info *) frame->rdi); default: return -ENOSYS; } diff --git a/examples/typephp-os/project.yml b/examples/typephp-os/project.yml index 693a8e30..8bf993c7 100644 --- a/examples/typephp-os/project.yml +++ b/examples/typephp-os/project.yml @@ -28,6 +28,9 @@ defines: - ASSEMBLER=1 - __BSD_VISIBLE=1 cxx-flags: + - -O2 + - -U_FORTIFY_SOURCE + - -D_FORTIFY_SOURCE=0 - -ffreestanding - -fno-builtin - -fno-stack-protector @@ -39,6 +42,9 @@ cxx-flags: - -fno-rtti - -fno-threadsafe-statics c-flags: + - -O2 + - -U_FORTIFY_SOURCE + - -D_FORTIFY_SOURCE=0 - -ffreestanding - -fno-builtin - -fno-stack-protector diff --git a/examples/typephp-os/tools/test-qemu.sh b/examples/typephp-os/tools/test-qemu.sh index ba29490e..ecc348cf 100755 --- a/examples/typephp-os/tools/test-qemu.sh +++ b/examples/typephp-os/tools/test-qemu.sh @@ -21,7 +21,7 @@ if timeout 35 qemu-system-x86_64 \ -no-shutdown \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ >"${log}" 2>&1 \ - <<< $'\ndate\nuname\nuname -a\necho Hello TypePHP userspace\nhello Dynamically loaded\ntnhello alpha beta\nsystest\nbuiltins\nmissing\nbad\nls /BIN\ncat HELLO.TXT\ntouch /EXPAND/F62.TXT\nls /EXPAND\nwrite NOTE.TXT Hello from Ring 3\ncat NOTE.TXT\ntouch EMPTY.TXT\nmkdir TMP\nls\nrm NOTE.TXT\ncat NOTE.TXT\nrmdir TMP\ncd TMP\nmkdir WORK\ncd WORK\nwrite NOTE.TXT Nested directory write\ncat NOTE.TXT\nmkdir SUB\ncd SUB\nwrite DEEP.TXT Deep directory write\nmv DEEP.TXT MOVED.TXT\ncat MOVED.TXT\ncat DEEP.TXT\npwd\ncd ..\nrmdir SUB\nrm SUB/MOVED.TXT\nrmdir SUB\nls\nrm NOTE.TXT\ncd ..\nrmdir WORK\ncd WORK\nmemtest\nfault\nvmfault\nwrfault\ndate\npwd\ncd BIN\npwd\nls\ncd ..\ncd DOCS\npwd\nls\ncd ..\nls\n'; then + <<< $'\ndate\nuname\nuname -a\nfree\necho Hello TypePHP userspace\nhello Dynamically loaded\ntnhello alpha beta\nsystest\nbuiltins\nmissing\nbad\nls /BIN\ncat HELLO.TXT\ntouch /EXPAND/F62.TXT\nls /EXPAND\nwrite NOTE.TXT Hello from Ring 3\ncat NOTE.TXT\ntouch EMPTY.TXT\nmkdir TMP\nls\nrm NOTE.TXT\ncat NOTE.TXT\nrmdir TMP\ncd TMP\nmkdir WORK\ncd WORK\nwrite NOTE.TXT Nested directory write\ncat NOTE.TXT\nmkdir SUB\ncd SUB\nwrite DEEP.TXT Deep directory write\nmv DEEP.TXT MOVED.TXT\ncat MOVED.TXT\ncat DEEP.TXT\npwd\ncd ..\nrmdir SUB\nrm SUB/MOVED.TXT\nrmdir SUB\nls\nrm NOTE.TXT\ncd ..\nrmdir WORK\ncd WORK\nmemtest\nfault\nvmfault\nwrfault\ndate\npwd\ncd BIN\npwd\nls\ncd ..\ncd DOCS\npwd\nls\ncd ..\nls\n'; then status=0 else status=$? @@ -51,10 +51,15 @@ grep -q "Prime list: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 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, pwd, date, uname, cat, echo, write, touch, mkdir, rm, rmdir, mv, memtest, systest, builtins, fault, vmfault, wrfault" "${log}" +grep -q "Commands: ls, cd, pwd, date, uname, free, cat, echo, write, touch, mkdir, rm, rmdir, mv, memtest, systest, builtins, fault, vmfault, wrfault" "${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\r' "${log}" grep -Fq $'TypePHP-OS typephp-os 0.1 TypePHP Nano user mode x86_64\r' "${log}" +grep -q '^TypePHP-OS memory' "${log}" +grep -q '^RAM: total=.*used=.*free=' "${log}" +grep -q '^Kernel Zend arena: total=.*used=.*free=' "${log}" +grep -q '^Physical page pool: total=.*used=.*free=' "${log}" +grep -q '^ATA block cache: ' "${log}" grep -q '^Hello TypePHP userspace' "${log}" grep -q '^Dynamically loaded' "${log}" grep -Fq 'Hello World!string(6) "8.4.14"' "${log}" diff --git a/examples/typephp-os/user/README.md b/examples/typephp-os/user/README.md index cbb67dfb..3192d72f 100644 --- a/examples/typephp-os/user/README.md +++ b/examples/typephp-os/user/README.md @@ -37,6 +37,12 @@ The resident shell and its standalone C command sources live under `cmd/`. Reusable startup, syscall, POSIX/libc, C++ ABI, and math support lives under `runtime/` and is emitted only as `build/libtypephp-os.a`. +`nano/free.php` is the first ordinary shell command implemented primarily in +TypePHP. Its NativeFunction bridge only retrieves the kernel memory snapshot; +unit conversion, pool accounting, and presentation remain TypePHP code. This +is the preferred split for future commands: TypePHP owns policy and application +logic, while C/C++ is limited to the syscall or PHPX boundary. + The current shared userspace runtime provides `syscall`, `read`, `write`, `openat`, `open`, `close`, `lseek`, `getcwd`, `chdir`, `mkdir`, `rmdir`, `unlink`, `rename`, `stat`, `lstat`, `fstat`, `access`, `fsync`, `fdatasync`, `truncate`, diff --git a/examples/typephp-os/user/cmd/sh.c b/examples/typephp-os/user/cmd/sh.c index fc550008..31384775 100644 --- a/examples/typephp-os/user/cmd/sh.c +++ b/examples/typephp-os/user/cmd/sh.c @@ -61,8 +61,8 @@ int main(int argc, char **argv) (void) write(STDOUT_FILENO, "Ring 3 confirmed\n", sizeof("Ring 3 confirmed\n") - 1); (void) write(STDOUT_FILENO, - "Commands: ls, cd, pwd, date, uname, cat, echo, write, touch, mkdir, rm, rmdir, mv, memtest, systest, builtins, fault, vmfault, wrfault\n", - sizeof("Commands: ls, cd, pwd, date, uname, cat, echo, write, touch, mkdir, rm, rmdir, mv, memtest, systest, builtins, fault, vmfault, wrfault\n") - 1); + "Commands: ls, cd, pwd, date, uname, free, cat, echo, write, touch, mkdir, rm, rmdir, mv, memtest, systest, builtins, fault, vmfault, wrfault\n", + sizeof("Commands: ls, cd, pwd, date, uname, free, cat, echo, write, touch, mkdir, rm, rmdir, mv, memtest, systest, builtins, fault, vmfault, wrfault\n") - 1); for (;;) { char *arguments[9]; int argument_count = 0; diff --git a/examples/typephp-os/user/include/sys/syscall.h b/examples/typephp-os/user/include/sys/syscall.h index 9701609a..8da9b579 100644 --- a/examples/typephp-os/user/include/sys/syscall.h +++ b/examples/typephp-os/user/include/sys/syscall.h @@ -49,6 +49,7 @@ * numbers or semantics. */ #define SYS_typephp_spawn TYPEPHP_SYS_SPAWN #define SYS_typephp_rename TYPEPHP_SYS_RENAME +#define SYS_typephp_memory_info TYPEPHP_SYS_MEMORY_INFO long syscall(long number, ...); diff --git a/examples/typephp-os/user/nano/free.cc b/examples/typephp-os/user/nano/free.cc new file mode 100644 index 00000000..ce5d9c79 --- /dev/null +++ b/examples/typephp-os/user/nano/free.cc @@ -0,0 +1,20 @@ +#include +#include + +php::Int php_os_memory_value(php::Int field) +{ + typephp_os_memory_info info; + if (typephp_os_get_memory_info(&info) != 0) { + return -1; + } + switch (field) { + case 0: return static_cast(info.total_bytes); + case 1: return static_cast(info.kernel_reserved_bytes); + case 2: return static_cast(info.zend_total_bytes); + case 3: return static_cast(info.zend_free_bytes); + case 4: return static_cast(info.page_total_bytes); + case 5: return static_cast(info.page_free_bytes); + case 6: return static_cast(info.block_cache_bytes); + default: return -1; + } +} diff --git a/examples/typephp-os/user/nano/free.php b/examples/typephp-os/user/nano/free.php new file mode 100644 index 00000000..3dddc36c --- /dev/null +++ b/examples/typephp-os/user/nano/free.php @@ -0,0 +1,49 @@ + #include +long syscall(long number, ...); + int ioctl(int fd, unsigned long request, ...) { void *argument = 0; diff --git a/examples/typephp-os/user/runtime/memory.c b/examples/typephp-os/user/runtime/memory.c new file mode 100644 index 00000000..064c5151 --- /dev/null +++ b/examples/typephp-os/user/runtime/memory.c @@ -0,0 +1,9 @@ +#include +#include + +long syscall(long number, ...); + +int typephp_os_get_memory_info(typephp_os_memory_info *info) +{ + return (int) syscall(TYPEPHP_SYS_MEMORY_INFO, info); +}