feat(kernel): implement syscall-based ioctl support and improve ATA caching

- Replace int 0x80 with native x86-64 SYSCALL instruction for faster system calls
- Add syscall number 16 for ioctl support with Linux-compatible ABI
- Implement TIOCGWINSZ and TIOCNOTTY terminal ioctls for console size detection
- Add ENOTTY error code definition for inappropriate ioctl operations
- Increase ATA cache capacity from 128 to 16384 entries for better performance
- Change ATA cache from LRU eviction to direct mapping using bitwise AND
- Remove least recently used tracking from ATA cache entries
-
master
韩天峰 4 weeks ago
parent 235d07f7c3
commit 6340433fbe
  1. 2
      examples/typephp-os/Makefile
  2. 6
      examples/typephp-os/README.md
  3. 13
      examples/typephp-os/ROADMAP.md
  4. 33
      examples/typephp-os/THIRDPARTY.md
  5. 1
      examples/typephp-os/kernel/core/abi/error.c
  6. 1
      examples/typephp-os/kernel/core/abi/typephp_os_syscall.h
  7. 30
      examples/typephp-os/kernel/core/ata.c
  8. 16
      examples/typephp-os/kernel/core/process-entry.S
  9. 87
      examples/typephp-os/kernel/core/process.c
  10. 33
      examples/typephp-os/tools/fetch-mlibc.sh
  11. 1
      examples/typephp-os/tools/fetch-thirdparty.sh
  12. 14
      examples/typephp-os/tools/mlibc-demo-cross.ini
  13. 26
      examples/typephp-os/tools/mlibc-headers-smoke.c
  14. 30
      examples/typephp-os/tools/test-thirdparty.sh
  15. 9
      examples/typephp-os/user/cmd/systest.c
  16. 1
      examples/typephp-os/user/include/errno.h
  17. 18
      examples/typephp-os/user/include/sys/ioctl.h
  18. 1
      examples/typephp-os/user/include/sys/syscall.h
  19. 5
      examples/typephp-os/user/runtime/README.md
  20. 18
      examples/typephp-os/user/runtime/ioctl.c
  21. 4
      examples/typephp-os/user/runtime/syscall.S

@ -22,7 +22,7 @@ OPENLIBM_SOURCES := $(shell sed -n 's|^\(.*\.c\)$$|thirdparty/openlibm/\1|p' too
COMPILER_RT_SOURCES := $(shell awk '$$2 ~ /\.c$$/ { print "thirdparty/compiler-rt/" $$2 }' tools/compiler-rt-builtins-files.sha256)
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 kernel/core/abi/error.c kernel/core/abi/string.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)
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 \

@ -99,9 +99,9 @@ Run the automated serial-output smoke test with:
make test
```
To configure the mlibc header porting probe and build the restricted hosted
Toybox applet set, install Meson 1.3 or newer and run `make thirdparty-smoke`.
This is an integration audit, not part of the boot image.
To build and audit the restricted hosted Toybox applet set, run
`make thirdparty-smoke`. This is an integration audit, not part of the boot
image.
The Makefile compiles the startup sources under `boot/` directly. The 32-bit
Multiboot bootstrap cannot participate in the 64-bit payload link; the 64-bit

@ -28,10 +28,9 @@ behavior.
`wait`, pipes, threads, scheduling signals, and job control will not be
implemented. The shell may only launch one synchronous foreground ELF
through the private TypePHP-OS service.
- `ioctl` and `termios` are outside the current scope. Third-party programs
must not drive implementation of these low-priority terminal interfaces;
they can be adopted only after their selected build no longer requires the
interfaces or another generally useful subsystem justifies them.
- Keep `ioctl` request support deliberately narrow. The fixed serial/VGA
console provides `TIOCGWINSZ`; a complete termios subsystem remains outside
the current single-task shell requirements.
## Milestones
@ -90,10 +89,8 @@ behavior.
C commands and multiple tpc projects link the same platform archive.
Unavailable ABI functions remain explicit panic stubs.
Selected upstream LLVM compiler-rt builtins now provide 128-bit integer
helper symbols. mlibc 7.0 and a five-applet Toybox build are pinned as
porting probes; neither replaces the working userspace runtime yet because
mlibc exceeds the C++17 baseline and Toybox's common runtime still imports
`ioctl`.
helper symbols. A five-applet Toybox build is pinned as a porting probe but
does not yet replace the working userspace commands.
Single-task identity calls report PID/TID 1 for the resident shell, 2 for
its synchronous foreground command, and root UID/GID. Linux-compatible
wall/monotonic clock structures are exposed at the current one-second RTC

@ -28,9 +28,8 @@ Run the upstream integration probes separately:
make thirdparty-smoke
```
This target requires Meson 1.3 or newer for mlibc. It configures a headers-only
mlibc sysroot and builds a deliberately small hosted Toybox. Neither candidate
is installed into the TypePHP-OS disk image by this probe.
This target builds a deliberately small hosted Toybox and audits its undefined
ABI. It is not installed into the TypePHP-OS disk image by this probe.
## OpenLibm
@ -58,27 +57,6 @@ and TypePHP Nano userspace object set. The `builtins.elf` smoke command forces
signed and unsigned 128-bit division so the archive is tested as a real linker
dependency instead of merely being compiled.
## mlibc
- Upstream: <https://github.com/managarm/mlibc>
- Version: `v7.0.0`
- Commit: `7c2a178142625cc9852e59a1a090468c61a62d3b`
- Archive SHA-256: `56d62366a6a15bc3fd8741bebcb311ca543553f7b734b1e780aeae33691bd621`
The complete release tree is retained as a libc porting reference. The smoke
target configures mlibc's official Meson build in headers-only/demo-sysdeps
mode and compiles a TypePHP-OS API header probe. mlibc 7.0's implementation
build requires C++23 and GCC 13 or newer, while TypePHP-OS keeps C++17 as its
runtime baseline. Its implementation therefore does not replace the current
small libc yet; doing so also requires a real TypePHP-OS sysdeps port.
The mlibc 6 series does not have one uniform compiler baseline. Releases 6.0
and 6.1 request C++20 and do not contain the GCC 13 gate added later, so they
are more practical with an older compiler. Releases 6.2 and 6.3 already
request C++23. None of them satisfies TypePHP-OS's C++17 baseline unchanged;
using 6.0/6.1 would therefore be a separate port/toolchain choice rather than
a transparent downgrade of the pinned reference.
## Toybox
- Upstream: <https://codeberg.org/landley/toybox>
@ -93,7 +71,6 @@ host ABI is written to `build/thirdparty-smoke/toybox-undefined-symbols.txt`.
`ioctl` is a system-call API used by Toybox's shared C support library, not a
Toybox command. None of those five applet source files calls it directly, but
the common terminal/daemon helpers still leave an `ioctl` reference in the
hosted binary. Toybox is therefore intentionally not linked into TypePHP-OS.
The project will not implement `ioctl` or `termios` merely to satisfy it;
adoption requires pruning the unused common helpers or completing a different
compatible libc/runtime path.
hosted binary. TypePHP-OS now exposes the Linux-numbered syscall and implements
`TIOCGWINSZ` for its fixed console. Toybox still needs a freestanding build and
ABI audit before it can replace any existing command.

@ -26,6 +26,7 @@ char *strerror(int error)
case ENOTDIR: return "Not a directory";
case EISDIR: return "Is a directory";
case EINVAL: return "Invalid argument";
case ENOTTY: return "Inappropriate ioctl for device";
case EMFILE: return "Too many open files";
case EROFS: return "Read-only file system";
case ERANGE: return "Numerical result out of range";

@ -16,6 +16,7 @@ enum typephp_os_syscall_number {
TYPEPHP_SYS_MPROTECT = 10,
TYPEPHP_SYS_MUNMAP = 11,
TYPEPHP_SYS_BRK = 12,
TYPEPHP_SYS_IOCTL = 16,
TYPEPHP_SYS_ACCESS = 21,
TYPEPHP_SYS_GETPID = 39,
TYPEPHP_SYS_EXIT = 60,

@ -33,19 +33,20 @@ enum {
ATA_COMMAND_CACHE_FLUSH = 0xe7,
ATA_SECTOR_SIZE = 512,
ATA_TIMEOUT = 10000000,
ATA_CACHE_CAPACITY = 128,
/* TNHELLO.ELF is currently about 5 MiB. A power-of-two 8 MiB cache keeps
* one complete image resident so a second launch avoids ATA PIO, while a
* direct mapping keeps every sector lookup O(1). */
ATA_CACHE_CAPACITY = 16384,
PCI_CONFIG_ADDRESS = 0xcf8,
PCI_CONFIG_DATA = 0xcfc,
};
static int ata_initialized;
static uint64_t ata_cache_clock;
static uint64_t ata_cache_hit_count;
static uint64_t ata_cache_miss_count;
typedef struct {
uint32_t lba;
uint64_t last_used;
int valid;
unsigned char data[ATA_SECTOR_SIZE];
} ata_cache_entry;
@ -206,23 +207,9 @@ static int ata_write_sector_raw(uint32_t lba, const unsigned char *data)
static ata_cache_entry *ata_cache_slot(uint32_t lba, int *found)
{
ata_cache_entry *oldest = &ata_cache[0];
for (size_t index = 0; index < ATA_CACHE_CAPACITY; ++index) {
ata_cache_entry *entry = &ata_cache[index];
if (entry->valid && entry->lba == lba) {
*found = 1;
return entry;
}
if (!entry->valid) {
*found = 0;
return entry;
}
if (entry->last_used < oldest->last_used) {
oldest = entry;
}
}
*found = 0;
return oldest;
ata_cache_entry *entry = &ata_cache[lba & (ATA_CACHE_CAPACITY - 1u)];
*found = entry->valid && entry->lba == lba;
return entry;
}
int typephp_os_disk_read_sector(uint32_t lba, unsigned char *data)
@ -235,7 +222,6 @@ int typephp_os_disk_read_sector(uint32_t lba, unsigned char *data)
entry = ata_cache_slot(lba, &found);
if (found) {
++ata_cache_hit_count;
entry->last_used = ++ata_cache_clock;
memcpy(data, entry->data, ATA_SECTOR_SIZE);
return 1;
}
@ -245,7 +231,6 @@ int typephp_os_disk_read_sector(uint32_t lba, unsigned char *data)
}
entry->valid = 1;
entry->lba = lba;
entry->last_used = ++ata_cache_clock;
memcpy(entry->data, data, ATA_SECTOR_SIZE);
return 1;
}
@ -261,7 +246,6 @@ int typephp_os_disk_write_sector(uint32_t lba, const unsigned char *data)
(void) found;
entry->valid = 1;
entry->lba = lba;
entry->last_used = ++ata_cache_clock;
memcpy(entry->data, data, ATA_SECTOR_SIZE);
return 1;
}

@ -4,7 +4,21 @@
.global typephp_os_syscall_entry
.type typephp_os_syscall_entry, @function
.extern typephp_os_syscall_dispatch
.extern typephp_os_syscall_stack
.extern typephp_os_syscall_user_rsp
typephp_os_syscall_entry:
# SYSCALL leaves RSP unchanged, stores the user RIP in RCX and stores the
# user RFLAGS in R11. Save the untrusted user stack pointer before moving
# to the kernel-owned syscall stack, then construct the same IRET frame
# used by exceptions and the former interrupt-gate entry.
mov %rsp, typephp_os_syscall_user_rsp(%rip)
lea typephp_os_syscall_stack+65536(%rip), %rsp
pushq $0x1b
pushq typephp_os_syscall_user_rsp(%rip)
push %r11
pushq $0x23
push %rcx
# Save every general-purpose register. The saved RAX slot is overwritten
# with the syscall result before the frame is restored.
push %rbx
@ -120,7 +134,7 @@ typephp_os_exception_common:
.type typephp_os_enter_user, @function
typephp_os_enter_user:
# RDI = ELF entry, RSI = top of the user stack. Interrupts remain masked;
# int 0x80 is synchronous and the first process manager has no scheduler.
# SYSCALL is synchronous and the first process manager has no scheduler.
mov $0x1b, %ax
mov %ax, %ds
mov %ax, %es

@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| TypePHP OS |
+----------------------------------------------------------------------+
| Single foreground process, ELF64 loader and int 0x80 syscall core. |
| Single foreground process, ELF64 loader and x86-64 syscall core. |
| SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
*/
@ -34,7 +34,6 @@ enum {
USER_DATA_SELECTOR = 0x1b,
KERNEL_CODE_SELECTOR = 0x08,
TSS_SELECTOR = 0x28,
IDT_SYSCALL = 0x80,
MAX_USER_ARGUMENTS = 8,
USER_PATH_MAX = 128,
UTSNAME_LENGTH = 65,
@ -59,6 +58,13 @@ typedef struct {
long microseconds;
} user_timeval;
typedef struct {
uint16_t rows;
uint16_t columns;
uint16_t pixel_width;
uint16_t pixel_height;
} user_winsize;
enum {
ELF_PT_LOAD = 1,
ELF_PF_X = 1,
@ -215,9 +221,31 @@ extern uint64_t physical_page_available(void);
static uint64_t gdt[7] __attribute__((aligned(16)));
static idt_gate idt[256] __attribute__((aligned(16)));
static task_state_segment tss;
static unsigned char syscall_stack[64u * 1024u] __attribute__((aligned(16)));
unsigned char typephp_os_syscall_stack[64u * 1024u] __attribute__((aligned(16)));
uint64_t typephp_os_syscall_user_rsp;
static process_state foreground_process = {.pid = 1, .cwd = "/"};
enum {
IA32_EFER = 0xc0000080u,
IA32_STAR = 0xc0000081u,
IA32_LSTAR = 0xc0000082u,
IA32_FMASK = 0xc0000084u,
};
static uint64_t read_msr(uint32_t index)
{
uint32_t low;
uint32_t high;
__asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(index));
return ((uint64_t) high << 32u) | low;
}
static void write_msr(uint32_t index, uint64_t value)
{
__asm__ volatile("wrmsr" : : "c"(index), "a"((uint32_t) value),
"d"((uint32_t) (value >> 32u)) : "memory");
}
static void panic(const char *message)
{
typephp_os_write("Process panic: ", sizeof("Process panic: ") - 1);
@ -287,7 +315,8 @@ static void install_descriptor_tables(void)
gdt[3] = UINT64_C(0x00cff2000000ffff);
gdt[4] = UINT64_C(0x00affa000000ffff);
memset(&tss, 0, sizeof(tss));
tss.rsp0 = (uint64_t) (uintptr_t) (syscall_stack + sizeof(syscall_stack));
tss.rsp0 = (uint64_t) (uintptr_t)
(typephp_os_syscall_stack + sizeof(typephp_os_syscall_stack));
tss.iomap_base = sizeof(tss);
install_tss_descriptor((uint64_t) (uintptr_t) &tss, sizeof(tss) - 1u);
@ -314,10 +343,20 @@ static void install_descriptor_tables(void)
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");
/* STAR[47:32] selects kernel CS 0x08 and its following SS 0x10.
* SYSRET's selector arithmetic starts at 0x10, yielding user SS 0x1b
* and user CS 0x23. This kernel returns with IRETQ so that spawn/exit can
* replace the complete user context, but the entry ABI remains the native
* Linux x86-64 SYSCALL register convention. */
write_msr(IA32_STAR,
(UINT64_C(0x10) << 48u) | ((uint64_t) KERNEL_CODE_SELECTOR << 32u));
write_msr(IA32_LSTAR, (uint64_t) (uintptr_t) typephp_os_syscall_entry);
write_msr(IA32_FMASK, UINT64_C(0x700)); /* TF, IF and DF */
write_msr(IA32_EFER, read_msr(IA32_EFER) | UINT64_C(1));
}
static int read_exact(int fd, void *buffer, size_t size)
@ -402,6 +441,13 @@ static int load_user_elf_file(
if (segment.type != ELF_PT_LOAD) {
continue;
}
/* GNU ld can retain an empty PT_LOAD from the linker script when a
* tiny static executable has no data or bss sections. It maps no
* bytes and must not be rejected merely because its placeholder
* virtual address is zero. */
if (segment.filesz == 0 && segment.memsz == 0) {
continue;
}
if (segment.filesz > segment.memsz
|| !range_inside(segment.offset, segment.filesz, 0, image_size)
|| !range_inside(segment.vaddr, segment.memsz, region_begin, region_end)) {
@ -770,6 +816,34 @@ static long syscall_uname(user_utsname *result)
return 0;
}
static long syscall_ioctl(int fd, unsigned long request, void *argument)
{
enum {
LINUX_TIOCGWINSZ = 0x5413,
LINUX_TIOCNOTTY = 0x5422,
};
if (fd < STDIN_FILENO || fd > STDERR_FILENO) {
return -ENOTTY;
}
switch (request) {
case LINUX_TIOCGWINSZ: {
user_winsize *window = (user_winsize *) argument;
if (!user_buffer(window, sizeof(*window))) {
return -EFAULT;
}
window->rows = 25;
window->columns = 80;
window->pixel_width = 0;
window->pixel_height = 0;
return 0;
}
case LINUX_TIOCNOTTY:
default:
return -ENOTTY;
}
}
static unsigned int vm_protection(int protection)
{
unsigned int flags = 0;
@ -1153,6 +1227,9 @@ long typephp_os_syscall_dispatch(syscall_frame *frame)
return syscall_munmap(frame->rdi, frame->rsi);
case TYPEPHP_SYS_BRK:
return syscall_brk(frame->rdi);
case TYPEPHP_SYS_IOCTL:
return syscall_ioctl((int) frame->rdi, frame->rsi,
(void *) frame->rdx);
case TYPEPHP_SYS_ACCESS:
return syscall_access_path(AT_FDCWD, (const char *) frame->rdi,
(int) frame->rsi, 0);

@ -1,33 +0,0 @@
#!/usr/bin/env sh
set -eu
project_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
version=7.0.0
commit=7c2a178142625cc9852e59a1a090468c61a62d3b
archive_sha256=56d62366a6a15bc3fd8741bebcb311ca543553f7b734b1e780aeae33691bd621
target="${project_dir}/thirdparty/mlibc"
marker="${target}/.typephp-source-${version}"
if [ -f "${marker}" ] && [ -f "${target}/meson.build" ]; then
exit 0
fi
temporary=$(mktemp -d "${TMPDIR:-/tmp}/typephp-os-mlibc.XXXXXX")
trap 'rm -rf "${temporary}"' EXIT HUP INT TERM
archive="${temporary}/mlibc.tar.gz"
staging="${temporary}/installed"
echo "Downloading mlibc v${version} (${commit})"
curl -L --fail --retry 3 --silent --show-error -o "${archive}" \
"https://github.com/managarm/mlibc/archive/refs/tags/v${version}.tar.gz"
printf '%s %s\n' "${archive_sha256}" "${archive}" | sha256sum -c -
mkdir -p "${staging}"
tar -xzf "${archive}" -C "${staging}" --strip-components=1
test -f "${staging}/LICENSE"
mkdir -p "${project_dir}/thirdparty"
rm -rf "${target}"
mv "${staging}" "${target}"
printf '%s\n' "${commit}" > "${marker}"
echo "Installed mlibc v${version} in ${target}"

@ -6,5 +6,4 @@ tools_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
"${tools_dir}/fetch-openlibm.sh"
"${tools_dir}/fetch-compiler-rt-builtins.sh"
"${tools_dir}/fetch-mlibc.sh"
"${tools_dir}/fetch-toybox.sh"

@ -1,14 +0,0 @@
[binaries]
c = 'gcc'
cpp = 'g++'
ar = 'ar'
strip = 'strip'
[host_machine]
system = 'demo'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
needs_exe_wrapper = true

@ -1,26 +0,0 @@
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
_Static_assert(sizeof(uintptr_t) == 8, "TypePHP-OS requires a 64-bit mlibc ABI");
static void typecheck(void)
{
struct dirent entry;
struct stat status;
struct timespec timestamp;
struct utsname identity;
(void) entry;
(void) status;
(void) timestamp;
(void) identity;
}

@ -4,7 +4,6 @@ set -euo pipefail
project_dir=$(cd -- "$(dirname -- "$0")/.." && pwd)
build_dir="${project_dir}/build/thirdparty-smoke"
meson_command=${MESON:-meson}
if [[ ! -f "${project_dir}/build/libcompiler-rt-builtins.a" ]]; then
echo "compiler-rt archive is missing; run make compiler-rt-builtins first" >&2
@ -19,31 +18,6 @@ for symbol in __udivti3 __udivmodti4 __divti3 __modti3 __multi3; do
done
echo "compiler-rt builtins archive: OK"
if ! command -v "${meson_command}" >/dev/null 2>&1; then
echo "Meson 1.3 or newer is required for the mlibc headers probe" >&2
exit 1
fi
mlibc_build="${build_dir}/mlibc-build"
mlibc_sysroot="${build_dir}/mlibc-sysroot"
rm -rf "${mlibc_build}" "${mlibc_sysroot}"
"${meson_command}" setup \
"${mlibc_build}" "${project_dir}/thirdparty/mlibc" \
--cross-file "${project_dir}/tools/mlibc-demo-cross.ini" \
--prefix=/usr \
-Dheaders_only=true \
-Dposix_option=enabled \
-Dlinux_option=disabled \
-Dglibc_option=disabled \
-Dbsd_option=disabled
DESTDIR="${mlibc_sysroot}" "${meson_command}" install --quiet -C "${mlibc_build}"
compiler_headers=$(gcc -print-file-name=include)
gcc -std=c11 -ffreestanding -fsyntax-only -nostdinc \
-isystem "${mlibc_sysroot}/usr/include" \
-isystem "${compiler_headers}" \
"${project_dir}/tools/mlibc-headers-smoke.c"
echo "mlibc public-header ABI probe: OK"
toybox_source="${project_dir}/thirdparty/toybox"
toybox_config="${build_dir}/toybox.config"
mkdir -p "${build_dir}"
@ -67,8 +41,8 @@ if grep -Eq '^(fork|vfork|execv|execve|execvp|posix_spawn)$' "${toybox_symbols}"
fi
echo "Toybox selected applets build: OK"
if grep -qx ioctl "${toybox_symbols}"; then
echo "Toybox install: deferred (the common runtime still references unsupported ioctl)"
echo "Toybox ABI audit: common runtime imports the supported ioctl entry point"
else
echo "Toybox install: ABI audit no longer reports ioctl; reassess target linking"
echo "Toybox ABI audit: common runtime does not import ioctl"
fi
echo "Toybox ABI report: ${toybox_symbols}"

@ -1,6 +1,8 @@
#include <dirent.h>
#include <fcntl.h>
#include <stddef.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
@ -38,6 +40,7 @@ int main(int argc, char **argv)
struct timespec realtime;
struct timespec monotonic;
struct timespec resolution;
struct winsize window;
DIR *directory;
struct dirent *entry;
int found_hello = 0;
@ -100,6 +103,12 @@ int main(int argc, char **argv)
|| getuid() != 0 || geteuid() != 0 || getgid() != 0 || getegid() != 0) {
return fail("single-task identity");
}
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &window) != 0
|| window.ws_row != 25 || window.ws_col != 80
|| window.ws_xpixel != 0 || window.ws_ypixel != 0
|| ioctl(STDOUT_FILENO, TIOCNOTTY) != -1 || errno != ENOTTY) {
return fail("ioctl console ABI");
}
if (gettimeofday(&wall, NULL) != 0 || wall.tv_sec <= 0
|| clock_gettime(CLOCK_REALTIME, &realtime) != 0
|| clock_gettime(CLOCK_MONOTONIC, &monotonic) != 0

@ -16,6 +16,7 @@ int *__errno_location(void);
#define EISDIR 21
#define EINVAL 22
#define EMFILE 24
#define ENOTTY 25
#define EROFS 30
#define ERANGE 34
#define ENAMETOOLONG 36

@ -0,0 +1,18 @@
#ifndef TYPEPHP_OS_USER_SYS_IOCTL_H
#define TYPEPHP_OS_USER_SYS_IOCTL_H
/* Linux-compatible terminal request values and winsize layout. */
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};
#define TIOCGWINSZ 0x5413UL
#define TIOCSWINSZ 0x5414UL
#define TIOCNOTTY 0x5422UL
int ioctl(int fd, unsigned long request, ...);
#endif

@ -14,6 +14,7 @@
#define SYS_mprotect TYPEPHP_SYS_MPROTECT
#define SYS_munmap TYPEPHP_SYS_MUNMAP
#define SYS_brk TYPEPHP_SYS_BRK
#define SYS_ioctl TYPEPHP_SYS_IOCTL
#define SYS_access TYPEPHP_SYS_ACCESS
#define SYS_getpid TYPEPHP_SYS_GETPID
#define SYS_exit TYPEPHP_SYS_EXIT

@ -39,9 +39,8 @@ Selected LLVM compiler-rt 128-bit integer helpers are built separately as
Ring-3 `builtins` command deliberately generates signed and unsigned
division/remainder helper calls and verifies the results at runtime.
mlibc and Toybox are currently integration probes rather than runtime
dependencies. See `THIRDPARTY.md` for the tested boundary and the generated
Toybox ABI report.
Toybox is currently an integration probe rather than a runtime dependency.
See `THIRDPARTY.md` for the tested boundary and generated ABI report.
The archive and each consumer must use the same freestanding ABI flags and
PHP Nano/PHPX feature definitions. Those shared settings are maintained in the

@ -0,0 +1,18 @@
#include <stdarg.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
int ioctl(int fd, unsigned long request, ...)
{
void *argument = 0;
/* TIOCNOTTY has no third argument. The currently supported window-size
* requests use a pointer, as required by the Linux userspace ABI. */
if (request != TIOCNOTTY) {
va_list arguments;
va_start(arguments, request);
argument = va_arg(arguments, void *);
va_end(arguments);
}
return (int) syscall(SYS_ioctl, fd, request, argument);
}

@ -6,7 +6,7 @@
.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.
# registers, then use the native 64-bit fast-system-call instruction.
mov %rdi, %rax
mov %rsi, %rdi
mov %rdx, %rsi
@ -14,7 +14,7 @@ syscall:
mov %r8, %r10
mov %r9, %r8
mov 8(%rsp), %r9
int $0x80
syscall
cmp $-4095, %rax
jb 1f
neg %eax

Loading…
Cancel
Save