- Add crt0.S assembly startup code for user mode entry point - Create hello.php example application with basic system information output - Add hello.yml build configuration for nano user mode executable - Implement host.cc with system call interfaces and runtime initialization - Add linker script for proper user mode memory layout - Update Makefile with new user base addresses for shell and commands - Implement posix.c with POSIX compatibility layer using system calls - Update process.c with new user memory range constants and stack sizes - Add syscall.S assembly wrapper for Linux system call interface - Modify vm.c with expanded user address space mapping and cleanup - Update vmfault.c with correct shell memory address referencemaster
parent
d1085f68f8
commit
ce4bcdda4f
11 changed files with 511 additions and 28 deletions
@ -0,0 +1,23 @@ |
|||||||
|
.section .text.start, "ax" |
||||||
|
.code64 |
||||||
|
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
.extern main
|
||||||
|
_start: |
||||||
|
# Linux-compatible process entry stack: |
||||||
|
# argc, argv[], NULL, envp[], NULL, auxv[] |
||||||
|
xor %ebp, %ebp |
||||||
|
mov (%rsp), %rdi |
||||||
|
lea 8(%rsp), %rsi |
||||||
|
lea 16(%rsp,%rdi,8), %rdx |
||||||
|
and $-16, %rsp |
||||||
|
call main |
||||||
|
|
||||||
|
mov %eax, %edi |
||||||
|
mov $60, %eax |
||||||
|
int $0x80 |
||||||
|
ud2 |
||||||
|
.size _start, . - _start |
||||||
|
|
||||||
|
.section .note.GNU-stack, "", @progbits
|
||||||
@ -0,0 +1,11 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
function main(int $argc, array $argv): void |
||||||
|
{ |
||||||
|
echo "Hello World!"; |
||||||
|
var_dump(PHP_VERSION); |
||||||
|
var_dump($argc); |
||||||
|
var_dump($argv); |
||||||
|
var_dump(date('Y-m-d H:i:s', time())); |
||||||
|
var_dump(php_uname()); |
||||||
|
} |
||||||
@ -0,0 +1,64 @@ |
|||||||
|
name: typephp_os_user_hello |
||||||
|
mode: bin |
||||||
|
sources: |
||||||
|
- hello.php |
||||||
|
- host.cc |
||||||
|
- posix.c |
||||||
|
- ../../kernel/core/abi/libc.c |
||||||
|
- ../../kernel/core/abi/cxx.cpp |
||||||
|
- ../../kernel/core/abi/unimplemented.S |
||||||
|
- ../../thirdparty/openlibm/src |
||||||
|
objects: |
||||||
|
- ../../build/objects/nano-crt0.o |
||||||
|
- ../../build/objects/nano-syscall.o |
||||||
|
build-dir: ../../build/generated-user-hello |
||||||
|
output: ../../build/tnhello.elf |
||||||
|
cxx-std: c++17 |
||||||
|
include-paths: |
||||||
|
- ../../kernel/core/abi |
||||||
|
- ../../thirdparty/openlibm/include |
||||||
|
- ../../thirdparty/openlibm/src |
||||||
|
- ../../thirdparty/openlibm/amd64 |
||||||
|
defines: |
||||||
|
- TYPEPHP_NO_MAIN=1 |
||||||
|
- PHPX_NO_EXCEPTION=1 |
||||||
|
- PHPX_NO_RTTI=1 |
||||||
|
- PHP_NANO_NO_LIBC=1 |
||||||
|
- HAVE_SYS_UTSNAME_H=1 |
||||||
|
- __NO_CTYPE=1 |
||||||
|
- ZEND_MM_ERROR=0 |
||||||
|
- ZEND_MM_CUSTOM=0 |
||||||
|
- ASSEMBLER=1 |
||||||
|
- __BSD_VISIBLE=1 |
||||||
|
cxx-flags: |
||||||
|
- -ffreestanding |
||||||
|
- -fno-builtin |
||||||
|
- -fno-stack-protector |
||||||
|
- -fno-pic |
||||||
|
- -fno-pie |
||||||
|
- -m64 |
||||||
|
- -mno-red-zone |
||||||
|
- -mcmodel=small |
||||||
|
- -fno-rtti |
||||||
|
- -fno-threadsafe-statics |
||||||
|
c-flags: |
||||||
|
- -ffreestanding |
||||||
|
- -fno-builtin |
||||||
|
- -fno-stack-protector |
||||||
|
- -fno-pic |
||||||
|
- -fno-pie |
||||||
|
- -m64 |
||||||
|
- -mno-red-zone |
||||||
|
- -mcmodel=small |
||||||
|
asm-flags: |
||||||
|
- -m64 |
||||||
|
- -mno-red-zone |
||||||
|
- -mcmodel=small |
||||||
|
ld-flags: |
||||||
|
- -nostdlib |
||||||
|
- -no-pie |
||||||
|
- -Wl,-m,elf_x86_64 |
||||||
|
- -Wl,--build-id=none |
||||||
|
- -Wl,-T,examples/typephp-os/user/nano/linker.ld |
||||||
|
- -Wl,--defsym,USER_BASE=0x41000000 |
||||||
|
- -lgcc |
||||||
@ -0,0 +1,84 @@ |
|||||||
|
#include <php_nano_extension.h> |
||||||
|
#include <typephp_os_abi.h> |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <cstring> |
||||||
|
#include <sys/syscall.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
extern "C" int typephp_nano_project_main(); |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
constexpr std::uintptr_t arena_size = 24u * 1024u * 1024u; |
||||||
|
|
||||||
|
[[noreturn]] void raw_exit(int status) |
||||||
|
{ |
||||||
|
(void) syscall(SYS_exit, status); |
||||||
|
for (;;) { |
||||||
|
__asm__ volatile("pause"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" void typephp_os_write(const char *data, size_t size) |
||||||
|
{ |
||||||
|
(void) syscall(SYS_write, STDOUT_FILENO, data, size); |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" void typephp_os_panic(const char *message) |
||||||
|
{ |
||||||
|
static constexpr char prefix[] = "TypePHP user panic: "; |
||||||
|
typephp_os_write(prefix, sizeof(prefix) - 1); |
||||||
|
typephp_os_write(message, std::strlen(message)); |
||||||
|
typephp_os_write("\n", 1); |
||||||
|
raw_exit(127); |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" void phpx_no_exception_abort(const char *message) |
||||||
|
{ |
||||||
|
typephp_os_panic(message); |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" void php_nano_host_system_time( |
||||||
|
std::int64_t *seconds, std::int32_t *microseconds) |
||||||
|
{ |
||||||
|
*seconds = static_cast<std::int64_t>(syscall(SYS_time, nullptr)); |
||||||
|
*microseconds = 0; |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" std::uint64_t php_nano_host_monotonic_nanoseconds() |
||||||
|
{ |
||||||
|
return static_cast<std::uint64_t>(syscall(SYS_time, nullptr)) |
||||||
|
* UINT64_C(1000000000); |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" void php_nano_host_sleep( |
||||||
|
std::uint64_t seconds, std::uint32_t nanoseconds) |
||||||
|
{ |
||||||
|
const auto now = static_cast<std::uint64_t>(syscall(SYS_time, nullptr)); |
||||||
|
const auto deadline = now + seconds + (nanoseconds != 0 ? 1u : 0u); |
||||||
|
while (static_cast<std::uint64_t>(syscall(SYS_time, nullptr)) < deadline) { |
||||||
|
__asm__ volatile("pause"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char **argv) |
||||||
|
{ |
||||||
|
const auto begin = static_cast<std::uintptr_t>(syscall(SYS_brk, 0)); |
||||||
|
const auto end = begin + arena_size; |
||||||
|
if (begin == static_cast<std::uintptr_t>(-1) |
||||||
|
|| end < begin |
||||||
|
|| static_cast<std::uintptr_t>(syscall(SYS_brk, end)) != end) { |
||||||
|
typephp_os_panic("unable to allocate the Nano runtime arena"); |
||||||
|
} |
||||||
|
typephp_os_memory_init(reinterpret_cast<void *>(begin), arena_size); |
||||||
|
php_nano_set_cli_arguments(argc, argv); |
||||||
|
if (php_nano_startup_composer_extensions() != SUCCESS) { |
||||||
|
typephp_os_panic("unable to start PHP Nano extensions"); |
||||||
|
} |
||||||
|
const int status = typephp_nano_project_main(); |
||||||
|
php_nano_shutdown_composer_extensions(); |
||||||
|
return status; |
||||||
|
} |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
OUTPUT_FORMAT(elf64-x86-64) |
||||||
|
OUTPUT_ARCH(i386:x86-64) |
||||||
|
ENTRY(_start) |
||||||
|
|
||||||
|
PHDRS |
||||||
|
{ |
||||||
|
text PT_LOAD FILEHDR PHDRS FLAGS(5); |
||||||
|
data PT_LOAD FLAGS(6); |
||||||
|
stack PT_GNU_STACK FLAGS(6); |
||||||
|
} |
||||||
|
|
||||||
|
SECTIONS |
||||||
|
{ |
||||||
|
. = USER_BASE + SIZEOF_HEADERS; |
||||||
|
|
||||||
|
.text : |
||||||
|
{ |
||||||
|
KEEP(*(.text.start)) |
||||||
|
*(.text .text.*) |
||||||
|
} :text |
||||||
|
.rodata : { *(.rodata .rodata.*) } :text |
||||||
|
|
||||||
|
. = ALIGN(4K); |
||||||
|
.data : { *(.data .data.*) } :data |
||||||
|
.bss (NOLOAD) : { *(COMMON) *(.bss .bss.*) } :data |
||||||
|
|
||||||
|
/DISCARD/ : { *(.comment) *(.eh_frame*) *(.note*) } |
||||||
|
} |
||||||
@ -0,0 +1,237 @@ |
|||||||
|
#include <errno.h> |
||||||
|
#include <dirent.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <string.h> |
||||||
|
#include <sys/mman.h> |
||||||
|
#include <sys/stat.h> |
||||||
|
#include <sys/syscall.h> |
||||||
|
#include <sys/time.h> |
||||||
|
#include <sys/utsname.h> |
||||||
|
#include <time.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include <typephp_os_syscall.h> |
||||||
|
|
||||||
|
static __attribute__((noreturn)) void unsupported(const char *name) |
||||||
|
{ |
||||||
|
static const char prefix[] = "unsupported TypePHP-OS user ABI: "; |
||||||
|
(void) syscall(TYPEPHP_SYS_WRITE, STDERR_FILENO, prefix, sizeof(prefix) - 1); |
||||||
|
(void) syscall(TYPEPHP_SYS_WRITE, STDERR_FILENO, name, strlen(name)); |
||||||
|
(void) syscall(TYPEPHP_SYS_WRITE, STDERR_FILENO, "\n", 1); |
||||||
|
(void) syscall(TYPEPHP_SYS_EXIT, 126); |
||||||
|
for (;;) { |
||||||
|
__asm__ volatile("pause"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ssize_t read(int fd, void *buffer, size_t count) |
||||||
|
{ |
||||||
|
return (ssize_t) syscall(TYPEPHP_SYS_READ, fd, buffer, count); |
||||||
|
} |
||||||
|
|
||||||
|
ssize_t write(int fd, const void *buffer, size_t count) |
||||||
|
{ |
||||||
|
return (ssize_t) syscall(TYPEPHP_SYS_WRITE, fd, buffer, count); |
||||||
|
} |
||||||
|
|
||||||
|
int close(int fd) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_CLOSE, fd); |
||||||
|
} |
||||||
|
|
||||||
|
off_t lseek(int fd, off_t offset, int whence) |
||||||
|
{ |
||||||
|
return (off_t) syscall(TYPEPHP_SYS_LSEEK, fd, offset, whence); |
||||||
|
} |
||||||
|
|
||||||
|
int openat(int directory_fd, const char *path, int flags, ...) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_OPENAT, directory_fd, path, flags, 0); |
||||||
|
} |
||||||
|
|
||||||
|
int open(const char *path, int flags, ...) |
||||||
|
{ |
||||||
|
return openat(AT_FDCWD, path, flags, 0); |
||||||
|
} |
||||||
|
|
||||||
|
int chdir(const char *path) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_CHDIR, path); |
||||||
|
} |
||||||
|
|
||||||
|
int mkdir(const char *path, mode_t mode) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_MKDIR, path, mode); |
||||||
|
} |
||||||
|
|
||||||
|
int unlink(const char *path) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_UNLINK, path); |
||||||
|
} |
||||||
|
|
||||||
|
int rmdir(const char *path) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_RMDIR, path); |
||||||
|
} |
||||||
|
|
||||||
|
int brk(void *address) |
||||||
|
{ |
||||||
|
return (void *) syscall(TYPEPHP_SYS_BRK, address) == address ? 0 : -1; |
||||||
|
} |
||||||
|
|
||||||
|
void *sbrk(intptr_t increment) |
||||||
|
{ |
||||||
|
const intptr_t current = syscall(TYPEPHP_SYS_BRK, 0); |
||||||
|
const intptr_t requested = current + increment; |
||||||
|
if ((increment > 0 && requested < current) |
||||||
|
|| (increment < 0 && requested > current) |
||||||
|
|| (increment != 0 && syscall(TYPEPHP_SYS_BRK, requested) != requested)) { |
||||||
|
errno = ENOMEM; |
||||||
|
return (void *) -1; |
||||||
|
} |
||||||
|
return (void *) current; |
||||||
|
} |
||||||
|
|
||||||
|
void *mmap(void *address, size_t length, int protection, int flags, int fd, off_t offset) |
||||||
|
{ |
||||||
|
return (void *) syscall(TYPEPHP_SYS_MMAP, |
||||||
|
address, length, protection, flags, fd, offset); |
||||||
|
} |
||||||
|
|
||||||
|
int mprotect(void *address, size_t length, int protection) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_MPROTECT, address, length, protection); |
||||||
|
} |
||||||
|
|
||||||
|
int munmap(void *address, size_t length) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_MUNMAP, address, length); |
||||||
|
} |
||||||
|
|
||||||
|
time_t time(time_t *result) |
||||||
|
{ |
||||||
|
return (time_t) syscall(TYPEPHP_SYS_TIME, result); |
||||||
|
} |
||||||
|
|
||||||
|
int gettimeofday(struct timeval *value, void *timezone) |
||||||
|
{ |
||||||
|
(void) timezone; |
||||||
|
value->tv_sec = time(NULL); |
||||||
|
value->tv_usec = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int clock_gettime(clockid_t clock_id, struct timespec *value) |
||||||
|
{ |
||||||
|
(void) clock_id; |
||||||
|
value->tv_sec = time(NULL); |
||||||
|
value->tv_nsec = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned int sleep(unsigned int seconds) |
||||||
|
{ |
||||||
|
const time_t deadline = time(NULL) + seconds; |
||||||
|
while (time(NULL) < deadline) { |
||||||
|
__asm__ volatile("pause"); |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int nanosleep(const struct timespec *duration, struct timespec *remaining) |
||||||
|
{ |
||||||
|
(void) remaining; |
||||||
|
sleep((unsigned int) duration->tv_sec + (duration->tv_nsec != 0)); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int uname(struct utsname *value) |
||||||
|
{ |
||||||
|
if (value == NULL) { |
||||||
|
errno = EFAULT; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
memset(value, 0, sizeof(*value)); |
||||||
|
memcpy(value->sysname, "TypePHP-OS", sizeof("TypePHP-OS")); |
||||||
|
memcpy(value->nodename, "typephp-os", sizeof("typephp-os")); |
||||||
|
memcpy(value->release, "0.1", sizeof("0.1")); |
||||||
|
memcpy(value->version, "TypePHP Nano user mode", sizeof("TypePHP Nano user mode")); |
||||||
|
memcpy(value->machine, "x86_64", sizeof("x86_64")); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int isatty(int fd) |
||||||
|
{ |
||||||
|
return fd >= STDIN_FILENO && fd <= STDERR_FILENO; |
||||||
|
} |
||||||
|
|
||||||
|
int rename(const char *old_path, const char *new_path) |
||||||
|
{ |
||||||
|
return (int) syscall(TYPEPHP_SYS_RENAME, old_path, new_path); |
||||||
|
} |
||||||
|
|
||||||
|
int access(const char *path, int mode) |
||||||
|
{ |
||||||
|
(void) path; |
||||||
|
(void) mode; |
||||||
|
unsupported("access"); |
||||||
|
} |
||||||
|
|
||||||
|
int stat(const char *path, struct stat *value) |
||||||
|
{ |
||||||
|
(void) path; |
||||||
|
(void) value; |
||||||
|
unsupported("stat"); |
||||||
|
} |
||||||
|
|
||||||
|
int lstat(const char *path, struct stat *value) |
||||||
|
{ |
||||||
|
(void) path; |
||||||
|
(void) value; |
||||||
|
unsupported("lstat"); |
||||||
|
} |
||||||
|
|
||||||
|
int fstat(int fd, struct stat *value) |
||||||
|
{ |
||||||
|
(void) fd; |
||||||
|
(void) value; |
||||||
|
unsupported("fstat"); |
||||||
|
} |
||||||
|
|
||||||
|
DIR *opendir(const char *path) |
||||||
|
{ |
||||||
|
(void) path; |
||||||
|
unsupported("opendir"); |
||||||
|
} |
||||||
|
|
||||||
|
struct dirent *readdir(DIR *directory) |
||||||
|
{ |
||||||
|
(void) directory; |
||||||
|
unsupported("readdir"); |
||||||
|
} |
||||||
|
|
||||||
|
int closedir(DIR *directory) |
||||||
|
{ |
||||||
|
(void) directory; |
||||||
|
unsupported("closedir"); |
||||||
|
} |
||||||
|
|
||||||
|
void rewinddir(DIR *directory) |
||||||
|
{ |
||||||
|
(void) directory; |
||||||
|
unsupported("rewinddir"); |
||||||
|
} |
||||||
|
|
||||||
|
int fsync(int fd) |
||||||
|
{ |
||||||
|
(void) fd; |
||||||
|
unsupported("fsync"); |
||||||
|
} |
||||||
|
|
||||||
|
int ftruncate(int fd, off_t length) |
||||||
|
{ |
||||||
|
(void) fd; |
||||||
|
(void) length; |
||||||
|
unsupported("ftruncate"); |
||||||
|
} |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
.section .text |
||||||
|
.code64 |
||||||
|
|
||||||
|
.global syscall
|
||||||
|
.type syscall, @function
|
||||||
|
.extern __errno_location
|
||||||
|
syscall: |
||||||
|
# Translate the System V variadic-call ABI to Linux x86-64 syscall |
||||||
|
# registers. TypePHP-OS currently enters the kernel through int 0x80. |
||||||
|
mov %rdi, %rax |
||||||
|
mov %rsi, %rdi |
||||||
|
mov %rdx, %rsi |
||||||
|
mov %rcx, %rdx |
||||||
|
mov %r8, %r10 |
||||||
|
mov %r9, %r8 |
||||||
|
mov 8(%rsp), %r9 |
||||||
|
int $0x80 |
||||||
|
cmp $-4095, %rax |
||||||
|
jb 1f |
||||||
|
neg %eax |
||||||
|
push %rax |
||||||
|
call __errno_location |
||||||
|
pop %rdx |
||||||
|
mov %edx, (%rax) |
||||||
|
mov $-1, %rax |
||||||
|
1: |
||||||
|
ret |
||||||
|
.size syscall, . - syscall |
||||||
|
|
||||||
|
.section .note.GNU-stack, "", @progbits
|
||||||
Loading…
Reference in new issue