From: Tulio A M Mendes Date: Sat, 14 Mar 2026 01:19:19 +0000 (-0300) Subject: feat: i686-adros cross-toolchain infrastructure + kernel test expansion X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=9b3281522b5fc89cf6ad98551ca47143d236acbe;p=AdrOS.git feat: i686-adros cross-toolchain infrastructure + kernel test expansion Toolchain Build System (toolchain/): - toolchain/build.sh: Automated 5-stage build script Stage 1: Binutils 2.42 (i686-adros assembler/linker) Stage 2: GCC 13.2 bootstrap (C only, no libc) Stage 3: Newlib 4.4.0 (C library with libgloss/adros stubs) Stage 4: GCC 13.2 full rebuild (C/C++ with Newlib sysroot) Stage 5: Bash 5.2.21 cross-compilation (optional, static) - toolchain/patches/binutils-adros.patch: config.sub, bfd/config.bfd, gas/configure.tgt, ld/configure.tgt Adds i686-adros as ELF32 target using i386 backend - toolchain/patches/gcc-adros.patch: config.sub, gcc/config.gcc, gcc/config/i386/adros.h, libgcc/config.host, crti-adros.S, crtn-adros.S Defines __adros__, __unix__, ELF32 format, crt0.o startup, -lc -ladros -lgcc link spec, i386 wchar/size/ptrdiff types - toolchain/patches/newlib-adros.patch: config.sub, newlib/configure.host, newlib/libc/include/sys/config.h, libgloss/configure.in, libgloss/adros/configure.in+Makefile.in, newlib/libc/sys/adros/ stubs SIGNAL_PROVIDED, MALLOC_PROVIDED, HAVE_OPENDIR flags - toolchain/README.md: Build prerequisites, usage, sysroot layout, troubleshooting guide ulibc Enhancements: - errno.h: Full POSIX errno set (sorted, no duplicates), matches kernel - ctype.h: Added iscntrl, isgraph, ispunct, isascii, isblank, toascii - signal.h: Added SA_RESTART, SA_NOCLDSTOP, SA_NOCLDWAIT, SA_NODEFER, SA_RESETHAND, SIG_ERR, sighandler_t typedef, signal() declaration Kernel Test Expansion: - fulltest.c: 3 new syscall tests - gettimeofday: verify epoch timestamp > 1e9 - mprotect: brk page, write, mprotect RW, verify success - getrlimit/setrlimit: get RLIMIT_NOFILE, set lower, read back, restore - smoke_test.exp: 3 new patterns (100 total) 100/100 smoke tests pass (11 sec), cppcheck clean. --- diff --git a/tests/smoke_test.exp b/tests/smoke_test.exp index 0e24178..c39fb04 100755 --- a/tests/smoke_test.exp +++ b/tests/smoke_test.exp @@ -139,6 +139,9 @@ set tests { {"pipe EOF" "\\[init\\] pipe EOF OK"} {"readdir /proc" "\\[init\\] readdir /proc OK"} {"readdir /bin" "\\[init\\] readdir /bin OK"} + {"gettimeofday" "\\[init\\] gettimeofday OK"} + {"mprotect" "\\[init\\] mprotect OK"} + {"getrlimit/setrlimit" "\\[init\\] getrlimit/setrlimit OK"} {"LZ4 Frame decomp" "\\[INITRD\\] LZ4"} } diff --git a/toolchain/README.md b/toolchain/README.md new file mode 100644 index 0000000..1ba2954 --- /dev/null +++ b/toolchain/README.md @@ -0,0 +1,118 @@ +# AdrOS Cross-Compilation Toolchain + +Build a complete `i686-adros` toolchain: **Binutils → GCC (bootstrap) → Newlib → GCC (full) → Bash**. + +## Prerequisites + +Install on Ubuntu/Debian: +```bash +sudo apt install build-essential texinfo libgmp-dev libmpfr-dev libmpc-dev libisl-dev wget +``` + +Install on Fedora: +```bash +sudo dnf install gcc gcc-c++ make texinfo gmp-devel mpfr-devel libmpc-devel isl-devel wget +``` + +## Quick Build + +```bash +# Build everything (installs to /opt/adros-toolchain by default) +sudo mkdir -p /opt/adros-toolchain && sudo chown $USER /opt/adros-toolchain +./toolchain/build.sh + +# Or specify a custom prefix +./toolchain/build.sh --prefix $HOME/adros-toolchain --jobs 8 + +# Skip Bash if you only need the C compiler +./toolchain/build.sh --skip-bash +``` + +Build takes approximately 20-40 minutes depending on hardware. + +## What Gets Built + +| Step | Component | Output | +|------|-----------|--------| +| 1 | Binutils 2.42 | `i686-adros-ld`, `i686-adros-as`, `i686-adros-objdump`, ... | +| 2 | GCC 13.2 (bootstrap) | `i686-adros-gcc` (C only, no libc) | +| 3 | Newlib 4.4.0 | `libc.a`, `libm.a` (installed to sysroot) | +| 4 | GCC 13.2 (full) | `i686-adros-gcc`, `i686-adros-g++` (C/C++ with Newlib) | +| 5 | Bash 5.2.21 | Statically linked `bash` binary for AdrOS | + +## Usage + +```bash +export PATH=/opt/adros-toolchain/bin:$PATH + +# Compile a C program +i686-adros-gcc -o hello hello.c + +# Compile with math library +i686-adros-gcc -o calc calc.c -lm + +# Static linking (default) +i686-adros-gcc -static -o myapp myapp.c +``` + +## Sysroot Layout + +``` +/opt/adros-toolchain/i686-adros/ +├── include/ # Newlib + AdrOS headers +│ ├── stdio.h # Newlib +│ ├── stdlib.h # Newlib +│ ├── sys/ # Newlib + AdrOS system headers +│ └── ... +├── lib/ +│ ├── libc.a # Newlib C library +│ ├── libm.a # Newlib math library +│ ├── libadros.a # AdrOS syscall stubs +│ ├── crt0.o # C runtime startup +│ └── libgcc.a # GCC support library +└── ... +``` + +## AdrOS Target Patches + +The `patches/` directory contains diffs that add `i686-adros` as a recognized +target in each component's build system: + +- **`binutils-adros.patch`**: `config.sub`, `bfd/config.bfd`, `gas/configure.tgt`, `ld/configure.tgt` +- **`gcc-adros.patch`**: `config.sub`, `gcc/config.gcc`, `gcc/config/i386/adros.h`, `libgcc/config.host`, `crti.S`/`crtn.S` +- **`newlib-adros.patch`**: `config.sub`, `newlib/configure.host`, `newlib/libc/include/sys/config.h`, `libgloss/configure.in`, autoconf files + +### Key GCC Target Header (`adros.h`) + +Defines for the AdrOS target: +- `__adros__`, `__AdrOS__`, `__unix__` preprocessor macros +- ELF32 object format, i386 architecture +- Startup: `crt0.o` → `_start` → `main()` → `exit()` +- Links: `-lc -ladros -lgcc` + +## Troubleshooting + +**"configure: error: cannot compute sizeof..."** +→ Normal for cross-compilation. The build script passes `--with-newlib` to avoid +running target executables on the host. + +**"crt0.o: No such file"** +→ Newlib hasn't been built yet. Run the full build script or build Newlib first. + +**GCC can't find headers** +→ Ensure `--with-sysroot` points to the correct sysroot directory. + +## Directory Structure + +``` +toolchain/ +├── build.sh # Master build script +├── README.md # This file +├── patches/ +│ ├── binutils-adros.patch +│ ├── gcc-adros.patch +│ └── newlib-adros.patch +├── build/ # (generated) Build directories +├── src/ # (generated) Downloaded source tarballs +└── logs/ # (generated) Build logs +``` diff --git a/toolchain/build.sh b/toolchain/build.sh new file mode 100755 index 0000000..53316fa --- /dev/null +++ b/toolchain/build.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env bash +# +# AdrOS Toolchain Builder +# +# Builds a complete i686-adros cross-compilation toolchain: +# 1. Binutils (assembler, linker) +# 2. GCC (bootstrap, C only, no libc headers) +# 3. Newlib (C library) +# 4. GCC (full rebuild with Newlib sysroot) +# 5. Bash (optional, cross-compiled) +# +# Usage: +# ./toolchain/build.sh [--prefix /opt/adros] [--jobs 4] [--skip-bash] +# +# Prerequisites: +# - GCC (host), G++, Make, Texinfo, GMP, MPFR, MPC, ISL (dev packages) +# - wget or git for downloading sources +# - ~4 GB disk space +# +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ADROS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# ---- Defaults ---- +PREFIX="/opt/adros-toolchain" +TARGET="i686-adros" +JOBS="$(nproc 2>/dev/null || echo 4)" +SKIP_BASH=0 + +# ---- Versions ---- +BINUTILS_VER="2.42" +GCC_VER="13.2.0" +NEWLIB_VER="4.4.0.20231231" +BASH_VER="5.2.21" + +BINUTILS_URL="https://ftp.gnu.org/gnu/binutils/binutils-${BINUTILS_VER}.tar.xz" +GCC_URL="https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER}/gcc-${GCC_VER}.tar.xz" +NEWLIB_URL="https://sourceware.org/pub/newlib/newlib-${NEWLIB_VER}.tar.gz" +BASH_URL="https://ftp.gnu.org/gnu/bash/bash-${BASH_VER}.tar.gz" + +# ---- Parse args ---- +while [[ $# -gt 0 ]]; do + case "$1" in + --prefix) PREFIX="$2"; shift 2 ;; + --jobs) JOBS="$2"; shift 2 ;; + --skip-bash) SKIP_BASH=1; shift ;; + --help|-h) + echo "Usage: $0 [--prefix DIR] [--jobs N] [--skip-bash]" + exit 0 ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac +done + +SYSROOT="${PREFIX}/${TARGET}" +BUILD_DIR="${ADROS_ROOT}/toolchain/build" +SRC_DIR="${ADROS_ROOT}/toolchain/src" +PATCH_DIR="${ADROS_ROOT}/toolchain/patches" +LOG_DIR="${ADROS_ROOT}/toolchain/logs" + +export PATH="${PREFIX}/bin:${PATH}" + +msg() { echo -e "\n\033[1;32m==>\033[0m \033[1m$1\033[0m"; } +err() { echo -e "\n\033[1;31m==> ERROR:\033[0m $1" >&2; exit 1; } +step() { echo -e " \033[1;34m->\033[0m $1"; } + +mkdir -p "$BUILD_DIR" "$SRC_DIR" "$LOG_DIR" "$SYSROOT" + +# ---- Download sources ---- +download() { + local url="$1" dest="$2" + if [[ -f "$dest" ]]; then + step "Already downloaded: $(basename "$dest")" + return + fi + step "Downloading $(basename "$dest")..." + wget -q --show-progress -O "$dest" "$url" +} + +extract() { + local archive="$1" dir="$2" + if [[ -d "$dir" ]]; then + step "Already extracted: $(basename "$dir")" + return + fi + step "Extracting $(basename "$archive")..." + case "$archive" in + *.tar.xz) tar xf "$archive" -C "$SRC_DIR" ;; + *.tar.gz) tar xzf "$archive" -C "$SRC_DIR" ;; + *) err "Unknown archive type: $archive" ;; + esac +} + +msg "Downloading sources" +download "$BINUTILS_URL" "$SRC_DIR/binutils-${BINUTILS_VER}.tar.xz" +download "$GCC_URL" "$SRC_DIR/gcc-${GCC_VER}.tar.xz" +download "$NEWLIB_URL" "$SRC_DIR/newlib-${NEWLIB_VER}.tar.gz" +[[ $SKIP_BASH -eq 0 ]] && download "$BASH_URL" "$SRC_DIR/bash-${BASH_VER}.tar.gz" + +msg "Extracting sources" +extract "$SRC_DIR/binutils-${BINUTILS_VER}.tar.xz" "$SRC_DIR/binutils-${BINUTILS_VER}" +extract "$SRC_DIR/gcc-${GCC_VER}.tar.xz" "$SRC_DIR/gcc-${GCC_VER}" +extract "$SRC_DIR/newlib-${NEWLIB_VER}.tar.gz" "$SRC_DIR/newlib-${NEWLIB_VER}" +[[ $SKIP_BASH -eq 0 ]] && extract "$SRC_DIR/bash-${BASH_VER}.tar.gz" "$SRC_DIR/bash-${BASH_VER}" + +# ---- Apply patches ---- +apply_patch() { + local src_dir="$1" patch_file="$2" marker="$1/.adros_patched_$(basename "$2")" + if [[ -f "$marker" ]]; then + step "Already patched: $(basename "$patch_file")" + return + fi + step "Applying $(basename "$patch_file") to $(basename "$src_dir")..." + patch -d "$src_dir" -p1 < "$patch_file" + touch "$marker" +} + +msg "Applying AdrOS target patches" +apply_patch "$SRC_DIR/binutils-${BINUTILS_VER}" "$PATCH_DIR/binutils-adros.patch" +apply_patch "$SRC_DIR/gcc-${GCC_VER}" "$PATCH_DIR/gcc-adros.patch" +apply_patch "$SRC_DIR/newlib-${NEWLIB_VER}" "$PATCH_DIR/newlib-adros.patch" + +# Copy libgloss stubs into Newlib source tree +if [[ ! -d "$SRC_DIR/newlib-${NEWLIB_VER}/libgloss/adros" ]]; then + step "Copying libgloss/adros/ into Newlib source tree..." + cp -r "$ADROS_ROOT/newlib/libgloss/adros" "$SRC_DIR/newlib-${NEWLIB_VER}/libgloss/adros" +fi + +# ---- Install sysroot headers ---- +msg "Installing sysroot headers" +step "Copying ulibc headers to ${SYSROOT}/include..." +mkdir -p "${SYSROOT}/include/sys" "${SYSROOT}/include/linux" +cp -r "$ADROS_ROOT/user/ulibc/include/"*.h "${SYSROOT}/include/" 2>/dev/null || true +cp -r "$ADROS_ROOT/user/ulibc/include/sys/"*.h "${SYSROOT}/include/sys/" 2>/dev/null || true +cp -r "$ADROS_ROOT/user/ulibc/include/linux/"*.h "${SYSROOT}/include/linux/" 2>/dev/null || true + +# Copy kernel headers needed by the toolchain +step "Copying kernel headers to sysroot..." +for h in errno.h syscall.h socket.h; do + [[ -f "$ADROS_ROOT/include/$h" ]] && cp "$ADROS_ROOT/include/$h" "${SYSROOT}/include/kernel_${h}" +done + +# ================================================================== +# STEP 1: Build Binutils +# ================================================================== +msg "Building Binutils ${BINUTILS_VER}" +mkdir -p "$BUILD_DIR/binutils" +cd "$BUILD_DIR/binutils" + +if [[ ! -f "$PREFIX/bin/${TARGET}-ld" ]]; then + "$SRC_DIR/binutils-${BINUTILS_VER}/configure" \ + --target="$TARGET" \ + --prefix="$PREFIX" \ + --with-sysroot="$SYSROOT" \ + --disable-nls \ + --disable-werror \ + 2>&1 | tee "$LOG_DIR/binutils-configure.log" + + make -j"$JOBS" 2>&1 | tee "$LOG_DIR/binutils-build.log" + make install 2>&1 | tee "$LOG_DIR/binutils-install.log" + step "Binutils installed: ${PREFIX}/bin/${TARGET}-ld" +else + step "Binutils already installed" +fi + +# ================================================================== +# STEP 2: Build GCC (bootstrap — no libc) +# ================================================================== +msg "Building GCC ${GCC_VER} (bootstrap, C only)" +mkdir -p "$BUILD_DIR/gcc-bootstrap" +cd "$BUILD_DIR/gcc-bootstrap" + +if [[ ! -f "$PREFIX/bin/${TARGET}-gcc" ]]; then + "$SRC_DIR/gcc-${GCC_VER}/configure" \ + --target="$TARGET" \ + --prefix="$PREFIX" \ + --with-sysroot="$SYSROOT" \ + --without-headers \ + --enable-languages=c \ + --disable-nls \ + --disable-shared \ + --disable-threads \ + --disable-libssp \ + --disable-libquadmath \ + --disable-libgomp \ + --disable-libatomic \ + --with-newlib \ + 2>&1 | tee "$LOG_DIR/gcc-bootstrap-configure.log" + + make -j"$JOBS" all-gcc all-target-libgcc \ + 2>&1 | tee "$LOG_DIR/gcc-bootstrap-build.log" + make install-gcc install-target-libgcc \ + 2>&1 | tee "$LOG_DIR/gcc-bootstrap-install.log" + step "Bootstrap GCC installed: ${PREFIX}/bin/${TARGET}-gcc" +else + step "Bootstrap GCC already installed" +fi + +# ================================================================== +# STEP 3: Build Newlib +# ================================================================== +msg "Building Newlib ${NEWLIB_VER}" +mkdir -p "$BUILD_DIR/newlib" +cd "$BUILD_DIR/newlib" + +if [[ ! -f "${SYSROOT}/lib/libc.a" ]]; then + "$SRC_DIR/newlib-${NEWLIB_VER}/configure" \ + --target="$TARGET" \ + --prefix="$PREFIX" \ + --disable-multilib \ + --enable-newlib-nano-malloc \ + --enable-newlib-io-long-long \ + --enable-newlib-io-c99-formats \ + --disable-newlib-supplied-syscalls \ + 2>&1 | tee "$LOG_DIR/newlib-configure.log" + + make -j"$JOBS" 2>&1 | tee "$LOG_DIR/newlib-build.log" + make install 2>&1 | tee "$LOG_DIR/newlib-install.log" + step "Newlib installed to sysroot" +else + step "Newlib already installed" +fi + +# ================================================================== +# STEP 4: Rebuild GCC (full, with Newlib) +# ================================================================== +msg "Rebuilding GCC ${GCC_VER} (full, with Newlib sysroot)" +mkdir -p "$BUILD_DIR/gcc-full" +cd "$BUILD_DIR/gcc-full" + +# Only rebuild if the full gcc doesn't link against newlib yet +if [[ ! -f "$BUILD_DIR/gcc-full/.built" ]]; then + "$SRC_DIR/gcc-${GCC_VER}/configure" \ + --target="$TARGET" \ + --prefix="$PREFIX" \ + --with-sysroot="$SYSROOT" \ + --enable-languages=c,c++ \ + --disable-nls \ + --disable-shared \ + --with-newlib \ + --disable-libssp \ + --disable-libquadmath \ + 2>&1 | tee "$LOG_DIR/gcc-full-configure.log" + + make -j"$JOBS" 2>&1 | tee "$LOG_DIR/gcc-full-build.log" + make install 2>&1 | tee "$LOG_DIR/gcc-full-install.log" + touch "$BUILD_DIR/gcc-full/.built" + step "Full GCC installed: ${PREFIX}/bin/${TARGET}-g++" +else + step "Full GCC already installed" +fi + +# ================================================================== +# STEP 5: Cross-compile Bash (optional) +# ================================================================== +if [[ $SKIP_BASH -eq 0 ]]; then + msg "Cross-compiling Bash ${BASH_VER}" + mkdir -p "$BUILD_DIR/bash" + cd "$BUILD_DIR/bash" + + if [[ ! -f "$BUILD_DIR/bash/bash" ]]; then + # Bash needs a config.cache for cross-compilation + cat > config.cache <<'CACHE_EOF' +ac_cv_func_mmap_fixed_mapped=no +ac_cv_func_setvbuf_reversed=no +ac_cv_func_strcoll_works=yes +ac_cv_func_working_mktime=yes +ac_cv_type_getgroups=gid_t +ac_cv_rl_version=8.2 +bash_cv_func_sigsetjmp=present +bash_cv_func_ctype_nonascii=no +bash_cv_must_reinstall_sighandlers=no +bash_cv_func_snprintf=yes +bash_cv_func_vsnprintf=yes +bash_cv_printf_a_format=no +bash_cv_pgrp_pipe=no +bash_cv_sys_named_pipes=missing +bash_cv_job_control_missing=present +bash_cv_sys_siglist=yes +bash_cv_under_sys_siglist=yes +bash_cv_opendir_not_robust=no +bash_cv_ulimit_maxfds=yes +bash_cv_getenv_redef=yes +bash_cv_getcwd_malloc=yes +bash_cv_type_rlimit=long +bash_cv_type_intmax_t=int +bash_cv_type_uintmax_t=unsigned +CACHE_EOF + + "$SRC_DIR/bash-${BASH_VER}/configure" \ + --host="$TARGET" \ + --prefix=/usr \ + --without-bash-malloc \ + --disable-nls \ + --cache-file=config.cache \ + CC="${TARGET}-gcc" \ + AR="${TARGET}-ar" \ + RANLIB="${TARGET}-ranlib" \ + CFLAGS="-Os -static" \ + LDFLAGS="-static" \ + 2>&1 | tee "$LOG_DIR/bash-configure.log" + + make -j"$JOBS" 2>&1 | tee "$LOG_DIR/bash-build.log" + step "Bash built: $BUILD_DIR/bash/bash" + + # Copy to AdrOS initrd + if [[ -d "$ADROS_ROOT/iso/boot" ]]; then + step "Installing bash to AdrOS filesystem..." + mkdir -p "$ADROS_ROOT/iso/bin" + cp "$BUILD_DIR/bash/bash" "$ADROS_ROOT/iso/bin/bash" + fi + else + step "Bash already built" + fi +fi + +# ================================================================== +# Summary +# ================================================================== +msg "Toolchain build complete!" +echo "" +echo " Prefix: $PREFIX" +echo " Target: $TARGET" +echo " Sysroot: $SYSROOT" +echo "" +echo " Tools:" +echo " ${TARGET}-gcc — C compiler" +echo " ${TARGET}-g++ — C++ compiler" +echo " ${TARGET}-ld — Linker" +echo " ${TARGET}-as — Assembler" +echo " ${TARGET}-ar — Archiver" +echo " ${TARGET}-objdump — Disassembler" +echo "" +echo " Usage:" +echo " export PATH=${PREFIX}/bin:\$PATH" +echo " ${TARGET}-gcc -o hello hello.c" +echo "" +if [[ $SKIP_BASH -eq 0 ]]; then + echo " Bash: $BUILD_DIR/bash/bash" +fi diff --git a/toolchain/patches/binutils-adros.patch b/toolchain/patches/binutils-adros.patch new file mode 100644 index 0000000..fb6e93a --- /dev/null +++ b/toolchain/patches/binutils-adros.patch @@ -0,0 +1,48 @@ +--- a/config.sub ++++ b/config.sub +@@ -1749,6 +1749,9 @@ + -dicos*) + os=-dicos + ;; ++ -adros*) ++ os=-adros ++ ;; + -nacl*) + ;; + -ios) +--- a/bfd/config.bfd ++++ b/bfd/config.bfd +@@ -659,6 +659,11 @@ + targ_selvecs= + targ64_selvecs=x86_64_elf64_vec + ;; ++ i[3-7]86-*-adros*) ++ targ_defvec=i386_elf32_vec ++ targ_selvecs= ++ targ64_selvecs=x86_64_elf64_vec ++ ;; + i[3-7]86-*-linux-*) + targ_defvec=i386_elf32_vec + targ_selvecs="iamcu_elf32_vec i386_pei_vec" +--- a/gas/configure.tgt ++++ b/gas/configure.tgt +@@ -224,6 +224,7 @@ + i386-*-*nt*) fmt=coff em=pe ;; + i386-*-rdos*) fmt=elf ;; + i386-*-darwin*) fmt=macho ;; ++ i386-*-adros*) fmt=elf ;; + + ia16-*-elf*) fmt=elf ;; + +--- a/ld/configure.tgt ++++ b/ld/configure.tgt +@@ -344,6 +344,9 @@ + targ_extra_libpath=$targ_extra_emuls + ;; + i[3-7]86-*-linux-*) targ_emul=elf_i386 ++ ;; ++i[3-7]86-*-adros*) targ_emul=elf_i386 ++ targ_extra_emuls="elf_i386" + ;; + i[3-7]86-*-redox*) targ_emul=elf_i386 + ;; diff --git a/toolchain/patches/gcc-adros.patch b/toolchain/patches/gcc-adros.patch new file mode 100644 index 0000000..e0ee3c8 --- /dev/null +++ b/toolchain/patches/gcc-adros.patch @@ -0,0 +1,145 @@ +--- a/config.sub ++++ b/config.sub +@@ -1749,6 +1749,9 @@ + -dicos*) + os=-dicos + ;; ++ -adros*) ++ os=-adros ++ ;; + -nacl*) + ;; + -ios) +--- a/gcc/config.gcc ++++ b/gcc/config.gcc +@@ -1020,6 +1020,12 @@ + i[34567]86-*-elf*) + tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h" + ;; ++i[34567]86-*-adros*) ++ tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/adros.h" ++ tmake_file="${tmake_file} i386/t-crtstuff" ++ use_gcc_stdint=wrap ++ default_use_cxa_atexit=yes ++ ;; + x86_64-*-elf*) + tm_file="${tm_file} i386/unix.h i386/att.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h" + ;; +--- /dev/null ++++ b/gcc/config/i386/adros.h +@@ -0,0 +1,69 @@ ++/* Target definitions for i386 AdrOS. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ ++This file is part of GCC. ++ ++GCC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 3, or (at your option) ++any later version. ++ ++GCC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++Under Section 7 of GPL version 3, you are granted additional ++permissions described in the GCC Runtime Library Exception, version ++3.1, as published by the Free Software Foundation. ++ ++You should have received a copy of the GNU General Public License and ++a copy of the GCC Runtime Library Exception along with this program; ++see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ++. */ ++ ++/* AdrOS is a 32-bit POSIX-like operating system */ ++ ++#undef TARGET_OS_CPP_BUILTINS ++#define TARGET_OS_CPP_BUILTINS() \ ++ do { \ ++ builtin_define ("__adros__"); \ ++ builtin_define ("__AdrOS__"); \ ++ builtin_define ("__unix__"); \ ++ builtin_assert ("system=adros"); \ ++ builtin_assert ("system=unix"); \ ++ builtin_assert ("system=posix"); \ ++ } while (0) ++ ++/* Use ELF object format */ ++#undef OBJECT_FORMAT_ELF ++#define OBJECT_FORMAT_ELF 1 ++ ++/* Default to 32-bit */ ++#undef TARGET_64BIT_DEFAULT ++#define TARGET_64BIT_DEFAULT 0 ++ ++/* Use crt0.o from libgloss/adros */ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC "crt0.o%s crti.o%s crtbegin.o%s" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC "crtend.o%s crtn.o%s" ++ ++/* Link against Newlib's libc and our libgloss stub library */ ++#undef LIB_SPEC ++#define LIB_SPEC "-lc -ladros -lgcc" ++ ++/* Dynamic linker — not used yet (static linking only for now) */ ++#undef LINK_SPEC ++#define LINK_SPEC "-m elf_i386 %{shared:-shared} %{static:-static} %{!static: %{rdynamic:-export-dynamic}}" ++ ++/* Use Newlib's stdint types */ ++#undef SIZE_TYPE ++#define SIZE_TYPE "unsigned int" ++ ++#undef PTRDIFF_TYPE ++#define PTRDIFF_TYPE "int" ++ ++#undef WCHAR_TYPE ++#define WCHAR_TYPE "int" ++ ++#undef WCHAR_TYPE_SIZE ++#define WCHAR_TYPE_SIZE 32 +--- a/libgcc/config.host ++++ b/libgcc/config.host +@@ -685,6 +685,10 @@ + i[34567]86-*-elf*) + tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" + ;; ++i[34567]86-*-adros*) ++ tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" ++ extra_parts="$extra_parts crti.o crtn.o" ++ ;; + x86_64-*-elf* | x86_64-*-rtems*) + tmake_file="$tmake_file i386/t-crtstuff t-crtstuff-pic t-libgcc-pic" + ;; +--- /dev/null ++++ b/libgcc/config/i386/crti-adros.S +@@ -0,0 +1,14 @@ ++/* crti.S for AdrOS — .init/.fini prologue */ ++ .section .init ++ .global _init ++ .type _init, @function ++_init: ++ push %ebp ++ mov %esp, %ebp ++ ++ .section .fini ++ .global _fini ++ .type _fini, @function ++_fini: ++ push %ebp ++ mov %esp, %ebp +--- /dev/null ++++ b/libgcc/config/i386/crtn-adros.S +@@ -0,0 +1,10 @@ ++/* crtn.S for AdrOS — .init/.fini epilogue */ ++ .section .init ++ pop %ebp ++ ret ++ ++ .section .fini ++ pop %ebp ++ ret ++ ++ .section .note.GNU-stack,"",@progbits diff --git a/toolchain/patches/newlib-adros.patch b/toolchain/patches/newlib-adros.patch new file mode 100644 index 0000000..43fafd9 --- /dev/null +++ b/toolchain/patches/newlib-adros.patch @@ -0,0 +1,146 @@ +--- a/config.sub ++++ b/config.sub +@@ -1749,6 +1749,9 @@ + -dicos*) + os=-dicos + ;; ++ -adros*) ++ os=-adros ++ ;; + -nacl*) + ;; + -ios) +--- a/newlib/configure.host ++++ b/newlib/configure.host +@@ -243,6 +243,10 @@ + i[3-7]86-*-rdos*) + sys_dir=rdos + ;; ++ i[3-7]86-*-adros*) ++ sys_dir=adros ++ newlib_cflags="${newlib_cflags} -DSIGNAL_PROVIDED -DHAVE_OPENDIR -DHAVE_SYSTEM -DMALLOC_PROVIDED" ++ ;; + i[3-7]86-*-netware*) + ;; + m68k-*-netware*) +--- a/newlib/libc/include/sys/config.h ++++ b/newlib/libc/include/sys/config.h +@@ -28,6 +28,14 @@ + #define __DYNAMIC_REENT__ + #endif + ++/* AdrOS target configuration */ ++#ifdef __adros__ ++#define _READ_WRITE_RETURN_TYPE int ++#define __DYNAMIC_REENT__ ++#define HAVE_SYSTEM ++#define HAVE_OPENDIR ++#endif ++ + /* RTEMS uses Newlib reentrancy, not dynamic */ + #ifdef __rtems__ + #define __DYNAMIC_REENT__ +--- /dev/null ++++ b/newlib/libc/sys/adros/Makefile.am +@@ -0,0 +1,10 @@ ++## AdrOS system directory — empty (syscalls are in libgloss/adros) ++AUTOMAKE_OPTIONS = cygnus ++INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) ++AM_CCASFLAGS = $(INCLUDES) ++ ++noinst_LIBRARIES = lib.a ++lib_a_SOURCES = ++lib_a_CCASFLAGS = $(AM_CCASFLAGS) ++ ++ACLOCAL_AMFLAGS = -I ../../.. +--- /dev/null ++++ b/newlib/libc/sys/adros/configure.in +@@ -0,0 +1,8 @@ ++AC_PREREQ(2.59) ++AC_INIT([newlib],[NEWLIB_VERSION]) ++AC_CONFIG_SRCDIR([Makefile.am]) ++AC_CANONICAL_SYSTEM ++AM_INIT_AUTOMAKE([cygnus]) ++AM_MAINTAINER_MODE ++AC_CONFIG_FILES([Makefile]) ++AC_OUTPUT +--- a/libgloss/configure.in ++++ b/libgloss/configure.in +@@ -100,6 +100,9 @@ + i[3-7]86-*-elf* | i[3-7]86-*-coff*) + AC_CONFIG_SUBDIRS([i386]) + ;; ++ i[3-7]86-*-adros*) ++ AC_CONFIG_SUBDIRS([adros]) ++ ;; + m32r-*-*) + AC_CONFIG_SUBDIRS([m32r]) + ;; +--- /dev/null ++++ b/libgloss/adros/configure.in +@@ -0,0 +1,21 @@ ++dnl AdrOS libgloss configure ++AC_PREREQ(2.59) ++AC_INIT([libgloss-adros],[0.1]) ++AC_CANONICAL_SYSTEM ++AM_INIT_AUTOMAKE([cygnus]) ++AM_MAINTAINER_MODE ++ ++AC_PROG_CC ++AC_PROG_AS ++AC_PROG_AR ++AC_PROG_RANLIB ++AM_PROG_AS ++ ++host_makefile_frag=${srcdir}/../config/default.mh ++AC_SUBST(host_makefile_frag) ++ ++AC_CONFIG_FILES([Makefile]) ++AC_OUTPUT +--- /dev/null ++++ b/libgloss/adros/Makefile.in +@@ -0,0 +1,44 @@ ++# Makefile for AdrOS libgloss (autotools-generated template) ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++ ++prefix = @prefix@ ++exec_prefix = @exec_prefix@ ++tooldir = $(exec_prefix)/$(target_alias) ++ ++INSTALL = @INSTALL@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_DATA = @INSTALL_DATA@ ++ ++CC = @CC@ ++AS = @AS@ ++AR = @AR@ ++RANLIB = @RANLIB@ ++ ++CFLAGS = -g ++ ++BSP = libadros.a ++OBJS = syscalls.o ++CRT0 = crt0.o ++ ++all: $(CRT0) $(BSP) ++ ++$(BSP): $(OBJS) ++ $(AR) rcs $@ $^ ++ $(RANLIB) $@ ++ ++crt0.o: crt0.S ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++syscalls.o: syscalls.c ++ $(CC) $(CFLAGS) -c $< -o $@ ++ ++install: all ++ $(INSTALL_DATA) $(CRT0) $(tooldir)/lib/$(CRT0) ++ $(INSTALL_DATA) $(BSP) $(tooldir)/lib/$(BSP) ++ ++clean: ++ rm -f $(OBJS) $(CRT0) $(BSP) ++ ++.PHONY: all install clean diff --git a/user/fulltest.c b/user/fulltest.c index a1d6e89..e0cd5cb 100644 --- a/user/fulltest.c +++ b/user/fulltest.c @@ -142,6 +142,11 @@ enum { SYSCALL_POSIX_SPAWN = 96, SYSCALL_SETUID = 76, SYSCALL_SETGID = 77, + SYSCALL_MOUNT = 126, + SYSCALL_GETTIMEOFDAY = 127, + SYSCALL_MPROTECT = 128, + SYSCALL_GETRLIMIT = 129, + SYSCALL_SETRLIMIT = 130, }; enum { @@ -285,6 +290,23 @@ struct timeval { uint32_t tv_usec; }; +struct rlimit { + uint32_t rlim_cur; + uint32_t rlim_max; +}; + +enum { + RLIMIT_CPU = 0, + RLIMIT_FSIZE = 1, + RLIMIT_DATA = 2, + RLIMIT_STACK = 3, + RLIMIT_CORE = 4, + RLIMIT_NOFILE = 5, + RLIMIT_AS = 6, + RLIMIT_NPROC = 7, + RLIM_INFINITY = 0xFFFFFFFFU, +}; + struct itimerval { struct timeval it_interval; struct timeval it_value; @@ -1313,6 +1335,30 @@ static int sys_sigsuspend(const uint32_t* mask) { return __syscall_fix(ret); } +static int sys_gettimeofday(struct timeval* tv) { + int ret; + __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_GETTIMEOFDAY), "b"(tv), "c"(0) : "memory"); + return __syscall_fix(ret); +} + +static int sys_mprotect(uintptr_t addr, uint32_t len, uint32_t prot) { + int ret; + __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_MPROTECT), "b"(addr), "c"(len), "d"(prot) : "memory"); + return __syscall_fix(ret); +} + +static int sys_getrlimit(int resource, struct rlimit* rlim) { + int ret; + __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_GETRLIMIT), "b"(resource), "c"(rlim) : "memory"); + return __syscall_fix(ret); +} + +static int sys_setrlimit(int resource, const struct rlimit* rlim) { + int ret; + __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_SETRLIMIT), "b"(resource), "c"(rlim) : "memory"); + return __syscall_fix(ret); +} + __attribute__((noreturn)) static void sys_exit(int code) { __asm__ volatile( "int $0x80\n" @@ -4177,6 +4223,71 @@ void _start(void) { } } + /* ---- gettimeofday test ---- */ + { + struct timeval tv; + tv.tv_sec = 0; tv.tv_usec = 0; + int r = sys_gettimeofday(&tv); + if (r == 0 && tv.tv_sec > 1000000000U) { + static const char msg[] = "[init] gettimeofday OK\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } else { + static const char msg[] = "[init] gettimeofday failed\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } + } + + /* ---- mprotect test ---- */ + { + /* Test mprotect on heap memory (brk region) — simpler than mmap */ + uintptr_t old_brk = sys_brk(0); + uintptr_t page = (old_brk + 0xFFFU) & ~(uintptr_t)0xFFFU; + uintptr_t new_brk = page + 4096; + uintptr_t r_brk = sys_brk(new_brk); + if (r_brk >= new_brk) { + *(volatile uint32_t*)page = 0xDEADBEEF; + int r = sys_mprotect(page, 4096, PROT_READ | PROT_WRITE); + if (r == 0) { + static const char msg[] = "[init] mprotect OK\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } else { + static const char msg[] = "[init] mprotect call failed\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } + } else { + static const char msg[] = "[init] mprotect brk failed\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } + } + + /* ---- getrlimit/setrlimit test ---- */ + { + struct rlimit rl; + int r = sys_getrlimit(RLIMIT_NOFILE, &rl); + if (r == 0 && rl.rlim_cur > 0 && rl.rlim_cur <= 1024) { + /* Try setting a lower soft limit */ + struct rlimit new_rl; + new_rl.rlim_cur = rl.rlim_cur / 2; + new_rl.rlim_max = rl.rlim_max; + int r2 = sys_setrlimit(RLIMIT_NOFILE, &new_rl); + /* Read back */ + struct rlimit check; + int r3 = sys_getrlimit(RLIMIT_NOFILE, &check); + if (r2 == 0 && r3 == 0 && check.rlim_cur == new_rl.rlim_cur) { + static const char msg[] = "[init] getrlimit/setrlimit OK\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } else { + static const char msg[] = "[init] setrlimit failed\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } + /* Restore */ + (void)sys_setrlimit(RLIMIT_NOFILE, &rl); + } else { + static const char msg[] = "[init] getrlimit failed\n"; + (void)sys_write(1, msg, (uint32_t)(sizeof(msg) - 1)); + } + } + // PIE lazy PLT/GOT binding test { int pid = sys_fork(); diff --git a/user/ulibc/include/ctype.h b/user/ulibc/include/ctype.h index a94095a..5bf1b09 100644 --- a/user/ulibc/include/ctype.h +++ b/user/ulibc/include/ctype.h @@ -11,5 +11,11 @@ static inline int isprint(int c) { return c >= 0x20 && c <= 0x7E; } static inline int toupper(int c) { return islower(c) ? c - 32 : c; } static inline int tolower(int c) { return isupper(c) ? c + 32 : c; } static inline int isxdigit(int c) { return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } +static inline int iscntrl(int c) { return (c >= 0 && c < 0x20) || c == 0x7F; } +static inline int isgraph(int c) { return c > 0x20 && c <= 0x7E; } +static inline int ispunct(int c) { return isgraph(c) && !isalnum(c); } +static inline int isascii(int c) { return (unsigned)c <= 0x7F; } +static inline int isblank(int c) { return c == ' ' || c == '\t'; } +static inline int toascii(int c) { return c & 0x7F; } #endif diff --git a/user/ulibc/include/errno.h b/user/ulibc/include/errno.h index a069abe..6886642 100644 --- a/user/ulibc/include/errno.h +++ b/user/ulibc/include/errno.h @@ -3,29 +3,49 @@ extern int errno; -#define EPERM 1 -#define ENOENT 2 -#define ESRCH 3 -#define EINTR 4 -#define EIO 5 -#define ENXIO 6 -#define EBADF 9 -#define ECHILD 10 -#define EAGAIN 11 -#define ENOMEM 12 -#define EACCES 13 -#define EFAULT 14 -#define EEXIST 17 -#define ENOTDIR 20 -#define EISDIR 21 -#define EINVAL 22 -#define EMFILE 24 -#define ENOSPC 28 -#define EPIPE 32 -#define ENOSYS 38 -#define ENOTEMPTY 39 -#define ENOLCK 37 -#define EWOULDBLOCK EAGAIN +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define EMFILE 24 +#define ENOTTY 25 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EPIPE 32 +#define ERANGE 34 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EAFNOSUPPORT 47 +#define EADDRINUSE 48 +#define ECONNRESET 54 +#define ENOTCONN 57 +#define ETIMEDOUT 60 +#define ECONNREFUSED 61 +#define EOVERFLOW 75 +#define EMSGSIZE 90 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define EOPNOTSUPP 95 +#define EWOULDBLOCK EAGAIN /* Convert raw syscall return to errno-style */ static inline int __syscall_ret(int r) { diff --git a/user/ulibc/include/signal.h b/user/ulibc/include/signal.h index ca73c19..2fa5951 100644 --- a/user/ulibc/include/signal.h +++ b/user/ulibc/include/signal.h @@ -27,7 +27,17 @@ #define SIGVTALRM 26 #define SIGPROF 27 -#define SA_SIGINFO 0x00000004U +#define SA_RESTART 0x10000000U +#define SA_SIGINFO 0x00000004U +#define SA_NOCLDSTOP 0x00000001U +#define SA_NOCLDWAIT 0x00000002U +#define SA_NODEFER 0x40000000U +#define SA_RESETHAND 0x80000000U + +#define SIG_ERR ((void (*)(int))-1) + +typedef void (*sighandler_t)(int); +sighandler_t signal(int signum, sighandler_t handler); #define SIG_DFL ((void (*)(int))0) #define SIG_IGN ((void (*)(int))1)