- 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