diff --git a/.gitattributes b/.gitattributes index 0b518af4199..5e472ae4bcc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,6 @@ * text=auto eol=lf -*.real linguist-language=Assembly \ No newline at end of file + +jinx-config linguist-language=Shell +host-recipes/* linguist-language=Shell +recipes/* linguist-language=Shell +source-recipes/* linguist-language=Shell diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..0e38fe5a9c3 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,13 @@ +# These are supported funding model platforms + +github: [Andy-Python-Programmer] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0b91c27727..6cd2246677d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,60 +1,41 @@ -name: Aero - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y nasm meson ninja-build - python3 -m pip install requests xbstrap - - name: Build the kernel and userland - run: ./aero.py --no-run - - name: Build kernel documentation - run: ./aero.py --document - - name: Upload built image as artifact - uses: actions/upload-artifact@v2 - with: - name: Aero - path: ./build/aero.iso - - name: Deploy documentation - uses: peaceiris/actions-gh-pages@v3 - if: github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./build/web/ - - run_tests: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y nasm meson ninja-build qemu-system-x86 - python3 -m pip install requests xbstrap - - name: Print QEMU version - run: qemu-system-x86_64 --version - - name: Run tests - run: RUST_BACKTRACE=1 ./aero.py --test --features=ci --bios uefi -- -display none -device isa-debug-exit,iobase=0xf4,iosize=0x04 +name: Aero + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + CARGO_TERM_COLOR: always + + RED: '\033[1;31m' + NOCOLOR: '\033[0m' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y nasm make + - name: Build Documentation + run: | + make doc + find ./target -type d -name .git -prune -exec rm -rf {} \; + - name: Formatting Check + run: | + make check_fmt + git diff-index --quiet HEAD -- || (printf "${RED}error${NOCOLOR}: formatting check failed, run \`make fmt\`\n" && exit 1) + - name: Deploy documentation + uses: peaceiris/actions-gh-pages@v3 + if: github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./target/doc/ diff --git a/.gitignore b/.gitignore index c75223baf8c..d4638961943 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,16 @@ base-files/doom1.wad # Wayland test client and server executables: (todo: remove these) base-files/client base-files/server + +# todo: remove these +debug + +# XXXXXXXXXXXXXXXX +3rdparty/ +.jinx-cache +sources/ +host-pkgs/ +host-builds/ +pkgs/ +builds/ +raw-data diff --git a/.gitpod.yml b/.gitpod.yml index 872746fe075..edb8e3da12d 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -11,4 +11,4 @@ ports: tasks: - init: ./aero.py --no-run - command: ./aero.py --only-run + command: ./aero.py --only-run --memory 32G diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000000..b6beaf6d696 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,18 @@ +edition = "2021" +newline_style = "Unix" + +# maximum length of comments. +comment_width = 100 +# break comments to fit on the line +wrap_comments = true +# convert `/* */` comments to `//` comments where possible +normalize_comments = true +# format code snippet included in doc comments. +format_code_in_doc_comments = true + +# merge imports from the same module into a single use +# statement. Conversely, imports from different modules +# are split into separate statements. +imports_granularity = "Module" +# `type` and `const` are put first, then macros and methods. +reorder_impl_items = true diff --git a/.vscode/settings.json b/.vscode/settings.json index 1ba4c2a7a7c..f4cfcd3638f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "rust-analyzer.linkedProjects": [ "./src/Cargo.toml", - "./userland/Cargo.toml" + // "./userland/Cargo.toml" ], "rust-analyzer.checkOnSave.allTargets": false, // "rust-analyzer.checkOnSave.extraArgs": [ @@ -16,4 +16,5 @@ "termios.h": "c", "termios-c_iflag.h": "c" }, + "rust-analyzer.check.command": "clippy", } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 746c0e124a1..1ab51c94ade 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,4 +36,6 @@ $ lldb (lldb) ```` -Check out the docs for your debugger for information about how to use the debugger. \ No newline at end of file +Check out the docs for your debugger for information about how to use the debugger. + +`./aero.py -- -netdev user,id=spider -device e1000,netdev=spider,id=ck_nic0 -object filter-dump,id=spider,netdev=spider,file=qemulog.log` \ No newline at end of file diff --git a/LICENSE b/LICENSE index 032ca942d9f..3aace0bbf52 100644 --- a/LICENSE +++ b/LICENSE @@ -633,7 +633,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 2021 Anhad Singh + Copyright (C) 2021-2023 Anhad Singh This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..990748f7183 --- /dev/null +++ b/Makefile @@ -0,0 +1,94 @@ +profile ?= release + +ifneq ($(filter $(profile), dev debug), ) + KERNEL_TARGET := src/target/x86_64-unknown-none/debug/aero_kernel +else + KERNEL_TARGET := src/target/x86_64-unknown-none/release/aero_kernel +endif + +jinx: + mkdir -p target + if [ ! -f "target/jinx" ]; then \ + curl -Lo target/jinx https://github.com/mintsuki/jinx/raw/353c468765dd9404bacba8e5626d0830528e4300/jinx; \ + chmod +x target/jinx; \ + fi + + # FIXME: autosync + mkdir -p target/cargo-home + cp build-support/rust/config.toml target/cargo-home/config.toml + +.PHONY: distro +distro: jinx + ./target/jinx build-all + +SOURCE_DIR := src +USERLAND_DIR := userland +USERLAND_TARGET := builds/userland/target/init + +.PHONY: clean +clean: + rm -rf $(SOURCE_DIR)/target + +.PHONY: deep-clean +deep-clean: clean + rm -rf target sysroot sources pkgs host-pkgs host-builds builds + +.PHONY: check +check: + cd $(SOURCE_DIR) && cargo check + +$(KERNEL_TARGET): $(shell find $(SOURCE_DIR) -type f -not -path '$(SOURCE_DIR)/target/*') + cd $(SOURCE_DIR) && cargo build --package aero_kernel --profile $(profile) + ./build-support/mkiso.sh $(KERNEL_TARGET) + +$(USERLAND_TARGET): $(shell find $(USERLAND_DIR) -type f -not -path '$(USERLAND_DIR)/target/*') + ./target/jinx rebuild userland + @$(MAKE) distro-image + +.PHONY: iso +iso: $(KERNEL_TARGET) + +.PHONY: distro-image +distro-image: distro + ./build-support/mkimage.sh + +QEMU_PATH ?= $(shell dirname $(shell which qemu-system-x86_64)) + +.PHONY: qemu +qemu: $(KERNEL_TARGET) $(USERLAND_TARGET) + ${QEMU_PATH}/qemu-system-x86_64 \ + -cdrom target/aero.iso \ + -m 8G \ + -serial stdio \ + --boot d -s \ + -enable-kvm \ + -cpu host,+vmx \ + -drive file=target/disk.img,if=none,id=NVME1,format=raw \ + -device nvme,drive=NVME1,serial=nvme \ + ${QEMU_FLAGS} + +# "qemu_perf" options: +# delay (default: 30) - the amount of microseconds between each sample. +delay ?= 30 + +.PHONY: qemu_perf +qemu_perf: $(KERNEL_TARGET) $(USERLAND_TARGET) + ${QEMU_PATH}/qemu-system-x86_64 -cdrom target/aero.iso -m 8G -serial stdio --boot d -s -drive file=target/disk.img,if=none,id=NVME1,format=raw -device nvme,drive=NVME1,serial=nvme -plugin './target/kern-profile.so,out=raw-data,delay=$(delay)' -d plugin -cpu max + +.PHONY: qemu_p +qemu_p: + ${QEMU_PATH}/qemu-system-x86_64 -cdrom target/aero.iso -m 8G -serial stdio --boot d -s -drive file=target/disk.img,if=none,id=NVME1,format=raw -device nvme,drive=NVME1,serial=nvme -d plugin -cpu max -qmp unix:/tmp/qmp.sock,server,nowait + +.PHONY: doc +doc: + cd src && cargo doc --package aero_kernel --release --target-dir=../target/doc/ + echo "" > target/doc/index.html +ifeq ($(open),yes) + xdg-open target/doc/index.html +endif + +fmt: + cd $(SOURCE_DIR) && cargo fmt + +check_fmt: + cd $(SOURCE_DIR) && cargo fmt -- --check diff --git a/README.md b/README.md index 0755d13ae90..1c13f332d82 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Aero supports *modern* PC features such as Long Mode, 5-level paging, and SMP (multicore), to name a few. ![workflow](https://github.com/Andy-Python-Programmer/aero/actions/workflows/build.yml/badge.svg) -[![lines_of_code](https://tokei.rs/b1/github/Andy-Python-Programmer/aero)](https://github.com/Andy-Python-Programmer/aero) +[![lines_of_code](https://img.shields.io/endpoint?url=https://andypythonappdevelop.npkn.net/f0d517/)](https://github.com/Andy-Python-Programmer/aero) [![discord](https://img.shields.io/discord/828564770063122432)](https://discord.gg/8gwhTTZwt8) **Is this a Linux distribution?** @@ -19,14 +19,8 @@ No, Aero runs its own kernel that does *not* originate from Linux and does not s **Official Discord Server**: # Screenshots - -

Aero running TCC in Qemu (the background image is by Rick Astley)

- - -

Aero running Quick JS in Qemu (the background image is by Rick Astley)

- - -

Aero running DOOM in Qemu (the background image is by Rick Astley)

+ +

Running DWM, mesa-demos and Alacritty in Aero!

# Features - 64-bit higher half kernel @@ -40,31 +34,27 @@ No, Aero runs its own kernel that does *not* originate from Linux and does not s # Goals * Creating a modern, safe, beautiful and fast operating system. -* Targetting modern 64-bit architectures and CPU features. +* Targeting modern 64-bit architectures and CPU features. * Good source-level compatibility with Linux so we can port programs over easily. * Making a usable OS which can run on real hardware, not just on emulators or virtual machines. # How to Build and Run Aero -Please make sure you have a **unix-like** host system before building -Aero. If you are using windows, its highly recommended to use WSL 2. +Please make sure you have a Linux host system before building +Aero. If you are using windows, use WSL 2. ## Dependencies Before building Aero, you need the following things installed: -- `rustc` should be the **latest nightly** -- `qemu` +- `rust` (should be the **latest nightly**) - `nasm` -- `g++` 5.1 or later -- `ninja` -- `parted` -- `meson` -- `python3` +- `qemu` (optional: required if you want to run it in the Qemu emulator) +- `make` ## Hardware The following are *not* requirements but are *recommendations*: -- ~15GB of free disk space +- ~15GB of free disk space (this will vary depending on the amount of packages you want to build) - \>= 8GB RAM - \>= 2 cores - Internet access @@ -81,63 +71,16 @@ $ cd aero ## Building Aero -Aero uses a custom build system, that wraps `cargo` and takes care of building the kernel and -userland for you. It also builds the initramfs and disk image for you. - -The main command we will focus on is `./aero.py`. The source code can be found in the -root of the repository and, as the file name states, it is written in Python. - -By default if you run `./aero.py` without any arguments it will build the kernel and userland -in release mode with debug symbols and run it in QEMU. You can configure the behavior of the -build system though. If you want to, you can use the `--help` option to read a brief description -of what it can do. - -The build system acknowledges few different build modes, which cannot be used together -and they are: `--clean`, `--check`, `--test` and `--document`. - -- `--clean` option will clean all the build outputs. -- `--check` will build the kernel and userland using cargo's `check` command, - this build mode will not produce a disk image, if you want one without actually - running Aero in the emulator read ahead -- `--test` will run the built-in Aero test suite -- `--document` will generate web-based docs using cargo's `doc` command -- `--sysroot` will build the full userland sysroot. If not passed, then the sysroot will only contain -the `aero_shell` and the `init` binaries. - - **Note**: This command will require a relatively large amount of storage -space. You may want to have upwards of 10 or 15 gigabytes available if building with full sysroot. - -Each of these modes can be used with additional flags, that will alter the behavior in different -ways, some of them will not work for some of these modes - for example: the `--la57` option -will not have any effect when you are simply checking or documenting the build. - -- `--debug` toggles off the release build flag when calling cargo. - - **Summary**: If the `--debug` flag is not passed then it will build Aero in release mode - and debug symbols will be avaliable. On the other hand, if the debug flag is passed - then it will be built in debug mode and debug symbols will be still avaliable. By default - Aero is built in release mode (with debug symbols) since it generates faster and smaller - binaries which are easier to test. -- `--no-run` prevents from running the built disk image in the emulator -- `--bios` lets you choose the firmware the emulator will use when booting Aero, - currently supported values are: `legacy` and `uefi` -- `--features` accepts a single comma-separated list of kernel crate features, please - keep in mind that there cannot be spaces in between the values -- `--target` lets you override the target architecture for which the kernel is built, - currently the default value is `x86_64-aero_os` -- `--la57` tells the emulator to use 5 level paging, if it supports it - -The built disk image is stored in the `build` directory under the name `aero.iso`. Both the -disk root and initramfs root are preserved in case you want to inspect them manually. - -## Running Aero in an emulator - -If you haven't used the `--no-run` option and you aren't using the `--check` or `--document` build -mode, the build system will run Aero in the emulator for you. - -## Nightly Images - -Want to give Aero a shot, without building it! You can go to the [latest job](https://github.com/Andy-Python-Programmer/aero/actions/workflows/build.yml?query=is%3Asuccess+branch%3Amaster) and download the latest nightly image (`aero.iso`), under artifacts. +```shell +make distro-image +make qemu + +# To build documentation run the following command. The documentation will be outputed +# to the `target/doc` directory. +# +# Optionally you can pass `open=yes` to open the documentation in the default browser. +make doc open=yes +``` # Contributing @@ -145,6 +88,8 @@ Contributions are absolutely, positively welcome and encouraged! Check out [CONT # License + + Aero 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 of the License, or diff --git a/aero.py b/aero.py deleted file mode 100755 index cd649be213b..00000000000 --- a/aero.py +++ /dev/null @@ -1,706 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (C) 2021-2022 The Aero Project Developers. -# -# This file is part of The Aero Project. -# -# Aero 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 of the License, or -# (at your option) any later version. -# -# Aero 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. -# -# You should have received a copy of the GNU General Public License -# along with Aero. If not, see . - -import argparse -import json -import os -import platform -import shutil -import subprocess -import sys -import tarfile - -from typing import List - - -def log_info(msg): - """ - Logs a message with info log level. - """ - print(f"\033[1m\033[92minfo\033[0m: {msg}") - - -def log_error(msg): - """ - Logs a message with error log level. - """ - print(f"\033[1m\033[91merror\033[0m: {msg}") - - -# Make sure requests is installed -try: - import requests - import xbstrap -except ImportError: - log_error('Please install required libraires using the following command:') - log_error(' - python3 -m pip install requests xbstrap') - - sys.exit(0) - - -OVMF_URL = 'https://github.com/aero-os/ovmf-prebuilt' -LIMINE_URL = 'https://github.com/limine-bootloader/limine' - -BUILD_DIR = 'build' -BUNDLED_DIR = 'bundled' -SYSROOT_DIR = 'sysroot' -EXTRA_FILES = 'extra-files' -SYSROOT_CARGO_HOME = os.path.join(SYSROOT_DIR, 'cargo-home') -BASE_FILES_DIR = 'base-files' - -LIMINE_TEMPLATE = """ -TIMEOUT=0 -VERBOSE=yes - -:aero -PROTOCOL=limine -KASLR=no -KERNEL_PATH=boot:///aero.elf -CMDLINE=term-background=background theme-background=0x50000000 - -MODULE_PATH=boot:///term_background.bmp -MODULE_CMDLINE=background - -MODULE_PATH=boot:///initramfs.cpio -MODULE_CMDLINE=initramfs -""" - - -class BuildInfo: - args: argparse.Namespace - target_arch: str - - def __init__(self, target_arch: str, args: argparse.Namespace): - self.target_arch = target_arch - self.args = args - - -def download_userland_host_rust(): - out_file = os.path.join(BUNDLED_DIR, "host-rust-prebuilt.tar.gz") - - # we have already cloned the toolchain - if os.path.exists(out_file): - return - - log_info("downloading prebuilt userland host rust toolchain") - - cmd = r""" - wget --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate "https://docs.google.com/uc?export=download&id=FILE_HASH" -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=FILE_HASH" -O OUTPUT_FILE && rm -rf /tmp/cookies.txt - """.replace("FILE_HASH", "1TTC9qa1z-KdLaQkhgMCYxLE5nuKg4gcx").replace("OUTPUT_FILE", out_file) - - subprocess.run(cmd, shell=True) - - log_info("extracting prebuilt userland host rust toolchain") - - # the toolchain is compressed, so we need to extract it - file = tarfile.open(out_file) - file.extractall(os.path.join(BUNDLED_DIR, "host-rust-prebuilt")) - file.close() - - -def get_userland_tool(): - toolchain = os.path.join(SYSROOT_DIR, "tools") - - if os.path.exists(toolchain): - return toolchain - - return os.path.join(BUNDLED_DIR, "host-rust-prebuilt/aero") - - -def get_userland_package(): - toolchain = os.path.join(SYSROOT_DIR, "packages") - - if os.path.exists(toolchain): - return toolchain - - return os.path.join(BUNDLED_DIR, "host-rust-prebuilt/aero") - - -def remove_prefix(string: str, prefix: str): - if string.startswith(prefix): - return string[len(prefix):] - else: - return string[:] - - -def parse_args(): - parser = argparse.ArgumentParser( - description="utility used to build aero kernel and userland") - - check_test = parser.add_mutually_exclusive_group() - - check_test.add_argument('--clean', - default=False, - action='store_true', - help='removes the build artifacts') - - check_test.add_argument('--check', - default=False, - action='store_true', - help='checks if aero builds correctly without packaging and running it') - - check_test.add_argument('--test', - default=False, - action='store_true', - help='runs the aero test suite') - - check_test.add_argument('--document', - default=False, - action='store_true', - help='generates the documentation for the aero kernel') - - parser.add_argument('--debug', - default=False, - action='store_true', - help='builds the kernel and userland in debug mode') - - parser.add_argument('--no-run', - default=False, - action='store_true', - help='doesn\'t run the built image in emulator when applicable') - - parser.add_argument('--only-run', - default=False, - action='store_true', - help='runs aero without rebuilding. ignores any build-related flags') - - parser.add_argument('--bios', - type=str, - default='legacy', - choices=['legacy', 'uefi'], - help='run aero using the selected BIOS') - - parser.add_argument('--features', - type=lambda x: x.split(','), - default=[], - help='additional features to build the kernel with') - - parser.add_argument('--target', - default='x86_64-aero_os', - help='override the target triple the kernel will be built for') - - parser.add_argument('--la57', - default=False, - action='store_true', - help='run emulator with 5 level paging support') - - parser.add_argument('--sysroot', - default=False, - action='store_true', - help='build the full userland sysroot. If disabled, then the sysroot will only contain the aero_shell and the init binaries') - - parser.add_argument('--disable-kvm', - default=False, - action='store_true', - help='disable KVM acceleration even if its available') - - parser.add_argument('remaining', - nargs=argparse.REMAINDER, - help='additional arguments to pass as the emulator') - - return parser.parse_args() - - -def run_command(args, **kwargs): - output = subprocess.run(args, **kwargs) - - return output.returncode, output.stdout, output.stderr - - -def download_bundled(): - if not os.path.exists(BUNDLED_DIR): - os.makedirs(BUNDLED_DIR) - - ovmf_path = os.path.join(BUNDLED_DIR, 'ovmf') - limine_path = os.path.join(BUNDLED_DIR, 'limine') - - if not os.path.exists(ovmf_path): - run_command(['git', 'clone', '--depth', '1', OVMF_URL, ovmf_path]) - - if not os.path.exists(limine_path): - run_command(['git', 'clone', '--branch', 'v4.x-branch-binary', - '--depth', '1', LIMINE_URL, limine_path]) - - if not os.path.exists(SYSROOT_DIR): - download_userland_host_rust() - - -def extract_artifacts(stdout): - result = [] - lines = stdout.splitlines() - - for line in lines: - info = json.loads(line) - executable = info['executable'] if 'executable' in info else None - - if executable: - result.append(info['executable']) - - return result - - -def build_cargo_workspace(cwd, command, args, cargo="cargo"): - code, _, _ = run_command([cargo, command, *args], cwd=cwd) - - if code != 0: - return None - - _, stdout, _ = run_command([cargo, command, *args, '--message-format=json'], - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, - cwd=cwd) - - return extract_artifacts(stdout) - - -def build_kernel(args): - command = 'build' - cmd_args = ['--package', 'aero_kernel', - '--target', f'.cargo/{args.target}.json'] - - if not args.debug: - cmd_args += ['--release'] - - if args.test: - command = 'test' - cmd_args += ['--no-run'] - elif args.check: - command = 'check' - elif args.document: - command = 'doc' - - if args.features: - cmd_args += ['--features', ','.join(args.features)] - - return build_cargo_workspace('src', command, cmd_args) - - -# Helper function for symlink since os.symlink uses path -# relative to the destination directory. -def symlink_rel(src, dst): - rel_path_src = os.path.relpath(src, os.path.dirname(dst)) - os.symlink(rel_path_src, dst) - - -def build_userland_sysroot(args): - if not os.path.exists(SYSROOT_DIR): - os.mkdir(SYSROOT_DIR) - - # FIXME(xbstrap): xbstrap does not copy over the extra-files/rust/config.toml - # file into the cargo home directory. - if not os.path.exists(SYSROOT_CARGO_HOME): - os.mkdir(SYSROOT_CARGO_HOME) - - cargo_sys_cfg = os.path.join(SYSROOT_CARGO_HOME, 'config.toml') - if not os.path.exists(cargo_sys_cfg): - cargo_cfg_fd = open(os.path.join( - EXTRA_FILES, 'rust', 'config.toml'), 'r') - cargo_cfg = cargo_cfg_fd.read() - cargo_cfg_fd.close() - - cargo_cfg = cargo_cfg.replace("@SOURCE_ROOT@", os.getcwd()) - cargo_cfg = cargo_cfg.replace( - "@BUILD_ROOT@", os.path.join(os.getcwd(), SYSROOT_DIR)) - - cargo_cfg_fd = open(cargo_sys_cfg, "w+") - cargo_cfg_fd.write(cargo_cfg) - cargo_cfg_fd.close() - - blink = os.path.join(SYSROOT_DIR, 'bootstrap.link') - - if not os.path.islink(blink): - # symlink the bootstrap.yml file in the src root to sysroot/bootstrap.link - symlink_rel('bootstrap.yml', blink) - - os.chdir(SYSROOT_DIR) - - args = { - "update": True, - "all": True, - "dry_run": False, - "check": False, - "recursive": False, - "paranoid": False, - "reset": False, - "hard_reset": False, - "only_wanted": False, - "keep_going": False, - - "progress_file": None, # file that receives machine-ready progress notifications - "reconfigure": False, - "rebuild": False - } - - namespace = argparse.Namespace(**args) - xbstrap.do_install(namespace) - - -def build_userland(args): - HOST_CARGO = "host-cargo/bin/cargo" - HOST_RUST = "host-rust/bin/rustc" - HOST_GCC = "host-gcc/bin/x86_64-aero-gcc" - HOST_BINUTILS = "host-binutils/x86_64-aero/bin" - PACKAGE_MLIBC = "mlibc" - - tool_dir = get_userland_tool() - pkg_dir = get_userland_package() - - def get_cargo(): return os.path.join('..', tool_dir, HOST_CARGO) - def get_rustc(): return os.path.join('..', tool_dir, HOST_RUST) - def get_gcc(): return os.path.join('..', tool_dir, HOST_GCC) - def get_binutils(): return os.path.join("..", tool_dir, HOST_BINUTILS) - def get_mlibc(): return os.path.join("..", pkg_dir, PACKAGE_MLIBC) - - command = 'build' - # TODO: handle the unbased architectures. - cmd_args = ["--target", "x86_64-unknown-aero-system", - - # cargo config - "--config", f"build.rustc = '{get_rustc()}'", - "--config", "build.target = 'x86_64-unknown-aero-system'", - "--config", f"build.rustflags = ['-C', 'link-args=-no-pie -B {get_binutils()} --sysroot {get_mlibc()}', '-lc']", - "--config", f"target.x86_64-unknown-aero-system.linker = '{get_gcc()}'", - - "-Z", "unstable-options"] - - if not args.debug: - cmd_args += ['--release'] - - if args.check: - command = 'check' - - if args.test: - return build_cargo_workspace('userland', 'build', ['--package', 'utest', *cmd_args], get_cargo()) - else: - return build_cargo_workspace('userland', command, cmd_args, get_cargo()) - - # TODO: Userland check - # elif args.check: - # command = 'check' - - -def generate_docs(args): - doc_dir = os.path.join('src', 'target', args.target, 'doc') - out_dir = os.path.join(BUILD_DIR, 'web') - - if os.path.exists(out_dir): - shutil.rmtree(out_dir) - - shutil.copytree('web', out_dir, dirs_exist_ok=True) - shutil.copytree(doc_dir, out_dir, dirs_exist_ok=True) - - -def prepare_iso(args, kernel_bin, user_bins): - log_info("preparing ISO") - - if not os.path.exists(BUILD_DIR): - os.makedirs(BUILD_DIR) - - iso_path = os.path.join(BUILD_DIR, 'aero.iso') - iso_root = os.path.join(BUILD_DIR, 'iso_root') - limine_path = os.path.join(BUNDLED_DIR, 'limine') - - if os.path.exists(iso_root): - shutil.rmtree(iso_root) - - os.makedirs(iso_root) - - shutil.copy(kernel_bin, os.path.join(iso_root, 'aero.elf')) - shutil.copy(os.path.join('src', '.cargo', 'term_background.bmp'), iso_root) - shutil.copy(os.path.join(limine_path, 'limine.sys'), iso_root) - shutil.copy(os.path.join(limine_path, 'limine-cd.bin'), iso_root) - shutil.copy(os.path.join(limine_path, 'limine-cd-efi.bin'), iso_root) - - efi_boot = os.path.join(iso_root, "EFI", "BOOT") - os.makedirs(efi_boot) - - shutil.copy(os.path.join(limine_path, 'BOOTAA64.EFI'), efi_boot) - shutil.copy(os.path.join(limine_path, 'BOOTX64.EFI'), efi_boot) - - sysroot_dir = os.path.join(SYSROOT_DIR, 'system-root') - shutil.copytree(BASE_FILES_DIR, sysroot_dir, dirs_exist_ok=True) - - # dynamic linker (ld.so) - mlibc = os.path.join(get_userland_package(), "mlibc") - # gcc libraries required for rust programs - gcc = os.path.join(get_userland_package(), "gcc") - - # FIXME - if "host-rust-prebuilt" in str(mlibc): - shutil.copytree(mlibc, sysroot_dir, dirs_exist_ok=True) - shutil.copytree(gcc, sysroot_dir, dirs_exist_ok=True) - - for file in user_bins: - bin_name = os.path.basename(file) - shutil.copy(file, os.path.join(sysroot_dir, "usr", "bin", bin_name)) - - def find(path) -> List[str]: - _, find_output, _ = run_command(['find', '.', '-type', 'f'], - cwd=path, - stdout=subprocess.PIPE) - - files_without_dot = filter( - lambda x: x != '.', find_output.decode('utf-8').splitlines()) - files_without_prefix = map( - lambda x: remove_prefix(x, './'), files_without_dot) - files = list(files_without_prefix) - - files.append("usr/lib/libiconv.so.2") - return files - - files = find(sysroot_dir) - - with open(os.path.join(iso_root, 'initramfs.cpio'), 'wb') as initramfs: - cpio_input = '\n'.join(files) - code, _, _ = run_command(['cpio', '-o', '-v'], - cwd=sysroot_dir, - stdout=initramfs, - stderr=subprocess.PIPE, - input=cpio_input.encode('utf-8')) - - with open(os.path.join(iso_root, 'limine.cfg'), 'w') as limine_cfg: - limine_cfg.write(LIMINE_TEMPLATE) - - code, _, xorriso_stderr = run_command([ - 'xorriso', '-as', 'mkisofs', '-b', 'limine-cd.bin', '-no-emul-boot', '-boot-load-size', '4', - '-boot-info-table', '--efi-boot', 'limine-cd-efi.bin', '-efi-boot-part', - '--efi-boot-image', '--protective-msdos-label', iso_root, '-o', iso_path - ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - if code != 0: - log_error('failed to create the ISO image') - log_error(xorriso_stderr.decode('utf-8')) - - return None - - limine_deploy = os.path.join(limine_path, 'limine-deploy') - - if not os.path.exists(limine_deploy): - code, _, limine_build_stderr = run_command(['make', '-C', limine_path], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - if code != 0: - log_error('failed to build `limine-deploy`') - log_error(limine_build_stderr.decode('utf8')) - exit(1) - - code, _, limine_deploy_stderr = run_command([limine_deploy, iso_path], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - if code != 0: - log_error('failed to install Limine') - log_error(limine_deploy_stderr) - - return None - - return iso_path - - -def run_in_emulator(build_info: BuildInfo, iso_path): - is_kvm_available = is_kvm_supported() - args = build_info.args - - qemu_args = ['-cdrom', iso_path, - '-m', '9800M', - '-smp', '1', - '-serial', 'stdio'] - - if args.bios == 'uefi': - qemu_args += ['-bios', - f'bundled/ovmf/ovmf-{build_info.target_arch}/OVMF.fd'] - - cmdline = args.remaining - - if '--' in cmdline: - cmdline.remove('--') - - if cmdline: - qemu_args += cmdline - - if is_kvm_available and not args.disable_kvm: - log_info("running with KVM acceleration enabled") - - if platform.system() == 'Darwin': - qemu_args += ['-accel', 'hvf', '-cpu', - 'qemu64,+la57' if args.la57 else 'qemu64'] - else: - qemu_args += ['-enable-kvm', '-cpu', - 'host,+la57' if args.la57 else 'host'] - else: - if build_info.target_arch == "aarch64": - qemu_args += ['-device', 'ramfb', - '-M', 'virt', '-cpu', 'cortex-a72'] - elif build_info.target_arch == "x86_64": - qemu_args += ["-cpu", "qemu64,+la57" if args.la57 else "qemu64"] - else: - log_error("unknown target architecture") - exit(1) - - qemu_binary = f'qemu-system-{build_info.target_arch}' - run_command([qemu_binary, *qemu_args]) - - -def get_sysctl(name: str) -> str: - """ - Shell out to sysctl(1) - - Returns the value as a string. - Non-leaf nodes will return the value for each sub-node separated by newline characters. - """ - status, stdout, stderr = run_command(["sysctl", "-n", name], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - if status != 0: - print("`sysctl` failed: ", end="") - print(stderr.decode()) - - return stdout.strip().decode() - - -def is_kvm_supported() -> bool: - """ - Returns True if KVM is supported on this machine - """ - - platform = sys.platform - - if platform == "darwin": - # Check for VMX support - cpu_features = get_sysctl("machdep.cpu.features") - vmx_support = "VMX" in cpu_features.split(' ') - - # Check for HVF support - hv_support = get_sysctl("kern.hv_support") == "1" - - return hv_support and vmx_support - - if platform == "linux": - kvm_path = "/dev/kvm" - - # Check if the `/dev/kvm` device exists. - if not os.path.exists(kvm_path): - return False - - # Read out the cpuinfo from `/proc/cpuinfo` - fd = open("/proc/cpuinfo") - cpuinfo = fd.read() - - # Parse the cpuinfo - cpuinfo_array = cpuinfo.split("\n\n") - processors_info = [] - - for cpu in cpuinfo_array: - ret = {} - for line in cpu.split("\n"): - try: - name, value = line.split(":") - - name = name.strip() - value = value.strip() - - ret[name] = value - except ValueError: - pass - - processors_info.append(ret) - - for processor in processors_info: - if processor["processor"] == "0": - # KVM acceleration can be used - if "vmx" in processor["flags"]: - return True - # KVM acceleration cannot be used - else: - return False - - fd.close() - - # KVM is not avaliable on Windows - return False - - -def main(): - args = parse_args() - - # arch-aero_os - target_arch = args.target.split('-')[0] - build_info = BuildInfo(target_arch, args) - - if build_info.target_arch == "aarch64" and not args.bios == "uefi": - log_error("aarch64 requires UEFI (help: run again with `--bios=uefi`)") - return - - download_bundled() - - if args.only_run: - iso_path = os.path.join(BUILD_DIR, 'aero.iso') - - if not os.path.exists(iso_path): - user_bins = build_userland(args) - - if not user_bins: - return - - kernel_bin = build_kernel(args) - - if not kernel_bin or args.check: - return - - kernel_bin = kernel_bin[0] - iso_path = prepare_iso(args, kernel_bin, user_bins) - run_in_emulator(args, iso_path) - elif args.clean: - src_target = os.path.join('src', 'target', args.target) - userland_target = os.path.join('userland', 'target') - - if os.path.exists(src_target): - shutil.rmtree(src_target) - - if os.path.exists(userland_target): - shutil.rmtree(userland_target) - elif args.sysroot: - build_userland_sysroot(args) - elif args.document: - build_kernel(args) - - generate_docs(args) - else: - user_bins = build_userland(args) - - if not user_bins: - return - - kernel_bin = build_kernel(args) - - if not kernel_bin or args.check: - return - - kernel_bin = kernel_bin[0] - iso_path = prepare_iso(args, kernel_bin, user_bins) - - if not args.no_run: - run_in_emulator(build_info, iso_path) - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/base-files/.bashrc b/base-files/.bashrc deleted file mode 100644 index bc8d04262b4..00000000000 --- a/base-files/.bashrc +++ /dev/null @@ -1,15 +0,0 @@ -PS1='\[\033[01;32m\]root@\h\[\033[00m\]:\[\033[01;36m\]\w\[\033[00m\]\$ ' - -HISTCONTROL=ignoredups -HISTSIZE=-1 -HISTFILESIZE=-1 - -alias ls="ls --color=auto" -alias clear='printf "\e[2J\e[H"' - -export PYTHONHOME="/usr/lib" - -# todo: https://github.com/sharkdp/bat/blob/master/src/bin/bat/directories.rs panics if not set? -export BAT_CONFIG_DIR="/cfg/bat" -export BAT_CACHE_PATH="/cache/bat" -export DISPLAY=:0 diff --git a/base-files/.curlrc b/base-files/.curlrc new file mode 100644 index 00000000000..56c4b7bb593 --- /dev/null +++ b/base-files/.curlrc @@ -0,0 +1 @@ +--ipv4 \ No newline at end of file diff --git a/base-files/bin b/base-files/bin new file mode 120000 index 00000000000..0b11bef6890 --- /dev/null +++ b/base-files/bin @@ -0,0 +1 @@ +/usr/bin \ No newline at end of file diff --git a/base-files/etc/X11/xinit/xinitrc b/base-files/etc/X11/xinit/xinitrc new file mode 100644 index 00000000000..0b6b361fd42 --- /dev/null +++ b/base-files/etc/X11/xinit/xinitrc @@ -0,0 +1,2 @@ +#!/usr/bin/sh +jwm & diff --git a/extra-files/xorg/xorg.conf b/base-files/etc/X11/xorg.conf similarity index 100% rename from extra-files/xorg/xorg.conf rename to base-files/etc/X11/xorg.conf diff --git a/base-files/etc/bash.bashrc b/base-files/etc/bash.bashrc new file mode 100644 index 00000000000..a738e73f468 --- /dev/null +++ b/base-files/etc/bash.bashrc @@ -0,0 +1,13 @@ +# If not running interactively, don't do anything +[[ $- != *i* ]] && return + +alias ls='ls --color=auto' +alias grep='grep --color=auto' + +PS1='\[\033[01;32m\]root@\h\[\033[00m\]:\[\033[01;36m\]\w\[\033[00m\]\$ ' + +HISTCONTROL=ignoredups +HISTSIZE=-1 +HISTFILESIZE=-1 + +export DISPLAY=:0 diff --git a/base-files/etc/hostname b/base-files/etc/hostname new file mode 100644 index 00000000000..b6e4a236707 --- /dev/null +++ b/base-files/etc/hostname @@ -0,0 +1 @@ +aero \ No newline at end of file diff --git a/base-files/etc/profile b/base-files/etc/profile new file mode 100644 index 00000000000..dcb78173695 --- /dev/null +++ b/base-files/etc/profile @@ -0,0 +1,49 @@ +# /etc/profile + +# This file was copied from my host Arch Linux installation. Credits to them :) + +# Append "$1" to $PATH when not already in. +# This function API is accessible to scripts in /etc/profile.d +append_path () { + case ":$PATH:" in + *:"$1":*) + ;; + *) + PATH="${PATH:+$PATH:}$1" + esac +} + +# Append our default paths +append_path '/usr/local/sbin' +append_path '/usr/local/bin' +append_path '/usr/bin' + +# Force PATH to be environment +export PATH + +# Load profiles from /etc/profile.d +if test -d /etc/profile.d/; then + for profile in /etc/profile.d/*.sh; do + test -r "$profile" && . "$profile" + done + unset profile +fi + +# Unload our profile API functions +unset -f append_path + +# Source global bash config, when interactive but not posix or sh mode +if test "$BASH" &&\ + test "$PS1" &&\ + test -z "$POSIXLY_CORRECT" &&\ + test "${0#-}" != sh &&\ + test -r /etc/bash.bashrc +then + . /etc/bash.bashrc +fi + +# Termcap is outdated, old, and crusty, kill it. +unset TERMCAP + +# Man is much better than us at figuring this out +unset MANPATH diff --git a/base-files/etc/resolv.conf b/base-files/etc/resolv.conf new file mode 100644 index 00000000000..27a94c07e56 --- /dev/null +++ b/base-files/etc/resolv.conf @@ -0,0 +1 @@ +nameserver 10.0.2.3 diff --git a/base-files/hello.asm b/base-files/hello.asm deleted file mode 100644 index ee386d97bf4..00000000000 --- a/base-files/hello.asm +++ /dev/null @@ -1,20 +0,0 @@ -global _start - -section .text -_start: - mov rdx, len - mov rcx, msg - mov rbx, 1 - mov rax, 1 ; SYS_WRITE - - syscall - - mov rbx, 0 - mov rax, 5 ; SYS_EXIT - syscall - - ud2 ; unreacheable - -section .data -msg db "Hello, world!", 0xa -len equ $ - msg \ No newline at end of file diff --git a/base-files/home/aero/a b/base-files/home/aero/a new file mode 100644 index 00000000000..6a904dd38ac --- /dev/null +++ b/base-files/home/aero/a @@ -0,0 +1,21 @@ +#!/usr/bin/bash + +echo "Running update-mime-database to get the mime database" +update-mime-database /usr/share/mime/ + +echo "Running gio-querymodules to generate gio cache" +gio-querymodules /usr/lib/gio/modules/ + +echo "Running glib-compile-schemas to get gtk3 working" +glib-compile-schemas /usr/share/glib-2.0/schemas/ + +echo "Running gdk-pixbuf-query-loaders to get gtk3 working" +gdk-pixbuf-query-loaders --update-cache + +echo "Running gtk-query-immodules-3.0 to get gtk3 working" +gtk-query-immodules-3.0 --update-cache + +echo "Running gtk-query-immodules-2.0 to get gtk2 working" +gtk-query-immodules-2.0 --update-cache + +/usr/libexec/webkit2gtk-4.0/MiniBrowser diff --git a/base-files/home/aero/test.c b/base-files/home/aero/test.c new file mode 100644 index 00000000000..a99e713a844 --- /dev/null +++ b/base-files/home/aero/test.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("Hello World, from Aero!\n"); + return 0; +} diff --git a/base-files/lib b/base-files/lib new file mode 120000 index 00000000000..6c1836ebc71 --- /dev/null +++ b/base-files/lib @@ -0,0 +1 @@ +/usr/lib \ No newline at end of file diff --git a/base-files/lib64 b/base-files/lib64 new file mode 120000 index 00000000000..6c1836ebc71 --- /dev/null +++ b/base-files/lib64 @@ -0,0 +1 @@ +/usr/lib \ No newline at end of file diff --git a/base-files/sbin b/base-files/sbin new file mode 120000 index 00000000000..0b11bef6890 --- /dev/null +++ b/base-files/sbin @@ -0,0 +1 @@ +/usr/bin \ No newline at end of file diff --git a/base-files/test.c b/base-files/test.c deleted file mode 100644 index f0f734d22fe..00000000000 --- a/base-files/test.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("Hello World, from Aero!\n"); - return 0; -} \ No newline at end of file diff --git a/base-files/wallpaper.png b/base-files/wallpaper.png new file mode 100644 index 00000000000..1c9f1c62716 Binary files /dev/null and b/base-files/wallpaper.png differ diff --git a/bochsrc.txt b/bochsrc.txt index 24626017673..5248ae51f7c 100644 --- a/bochsrc.txt +++ b/bochsrc.txt @@ -10,5 +10,3 @@ cpu: count=4, reset_on_triple_fault=0, model=corei7_haswell_4770, ip cpuid: 1g_pages=0, apic=x2apic debug: action=report ata0-master: type=disk, path="build/aero.iso", mode=flat -plugin_ctrl: e1000=1 -e1000: enabled=0, mac=fe:fd:de:ad:be:ef, ethmod=null diff --git a/bootstrap.yml b/bootstrap.yml deleted file mode 100644 index 451c02c6aed..00000000000 --- a/bootstrap.yml +++ /dev/null @@ -1,1459 +0,0 @@ -imports: - - file: bootstrap/xorg.yml - -general: - cargo: - config_toml: 'extra-files/rust/config.toml' - -sources: - - name: binutils - subdir: 'bundled' - git: 'git://sourceware.org/git/binutils-gdb.git' - tag: 'binutils-2_37' - version: '2.37' - patch-path-strip: 1 - - - name: gcc - subdir: 'bundled' - git: 'git://gcc.gnu.org/git/gcc.git' - tag: 'releases/gcc-11.2.0' - patch-path-strip: 1 - version: '11.2.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - regenerate: - # download_prerequisites should probably move to some "post_checkout" step. - - args: ['./contrib/download_prerequisites'] - workdir: '@THIS_SOURCE_DIR@' - - args: ['autoconf'] - workdir: '@THIS_SOURCE_DIR@/gcc' - - args: ['autoconf'] - workdir: '@THIS_SOURCE_DIR@/libstdc++-v3' - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/gmp-6.1.0/configfsf.sub'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/isl-0.18/config.sub'] - - args: ['cp', '-f', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/mpc-1.0.3/config.sub'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/mpfr-3.1.6/config.sub'] - - - name: mlibc - subdir: 'bundled' - # git: 'https://github.com/managarm/mlibc' - git: 'https://github.com/Andy-Python-Programmer/mlibc' - # 452: The functions FD_{CLR,ISSET,SET,ZERO} were renamed to __FD_{CLR,ISSET,SET,ZERO} and replaced by macros to match Wine's assumptions. - # 511: Musl's regex engine was added, implementing regcomp and regexec. This required some changes to the regex_t struct. - # 504, #580: In both the mlibc and Linux ABIs, a domainname member was added to struct utsname, which is a glibc extension. - # 311: Added all necessary fields in pthread_attr_t required for implementing all pthread_attr functions. - branch: 'abi-break' - commit: '58ceb6648eefd801a774ba5e87b032706105243d' - - - name: tzcode - subdir: 'bundled' - url: 'https://data.iana.org/time-zones/releases/tzcode2022a.tar.gz' - format: 'tar.gz' - version: '2022a' - - - name: tzdata - subdir: 'bundled' - sources_required: ['tzcode'] - url: 'https://data.iana.org/time-zones/releases/tzdata2022a.tar.gz' - format: 'tar.gz' - version: '2022a' - regenerate: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/../tzcode/.', '@THIS_SOURCE_DIR@/'] - - - name: rust - subdir: 'bundled' - git: 'https://github.com/rust-lang/rust.git' - branch: 'master' - commit: '22e491ac7ed454d34669151a8b6464cb643c9b41' - - - name: llvm - subdir: 'bundled' - git: 'https://github.com/llvm/llvm-project.git' - tag: 'llvmorg-13.0.0' - version: '13.0.0' - - # --------------------------------------------------------------------------- - # Rust patched crates start - # --------------------------------------------------------------------------- - - name: rust-libc - subdir: 'bundled' - git: 'https://github.com/Andy-Python-Programmer/libc.git' - branch: 'master' - commit: '54d72b34bd614f0081e0da01e6323c7c69f45395' - - - name: rust-num-cpus - subdir: 'bundled' - git: 'https://github.com/seanmonstar/num_cpus.git' - tag: 'v1.13.0' - version: '1.13.0' - - - name: rust-users - subdir: 'bundled' - git: 'https://github.com/ogham/rust-users.git' - tag: 'v0.11.0' - version: '0.11.0' - - - name: rust-patched-libs - subdir: 'bundled' - sources_required: - - name: rust-libc - recursive: true - - name: rust-num-cpus - recursive: true - - name: rust-users - recursive: true - # --------------------------------------------------------------------------- - # Rust patched crates end - # --------------------------------------------------------------------------- - - - name: python - subdir: 'bundled' - patch-path-strip: 1 - git: 'https://github.com/python/cpython.git' - tag: 'v3.8.2' - version: '3.8.2' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - regenerate: - - args: ['autoreconf', '-f', '-i'] - - - name: 'pkg-config' - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/pkg-config/pkg-config.git' - tag: 'pkg-config-0.29.2' - version: '0.29.2' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - regenerate: - - args: ['./autogen.sh'] - environ: - 'NOCONFIGURE': 'yes' - - - name: wayland - subdir: 'bundled' - git: 'https://github.com/wayland-project/wayland.git' - tag: '1.20.0' - version: '1.20.0' - - - name: libxtrans - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxtrans.git' - tag: 'xtrans-1.4.0' - version: '1.4.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - -tools: - # We could run an external pkg-config; however, we need the aclocal files. - # The easiest way to ensure that they are available is to just install pkg-config. - - name: host-pkg-config - exports_aclocal: true - from_source: pkg-config - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - - '--with-internal-glib' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install'] - - - name: host-autoconf-v2.69 - source: - name: autoconf-v2.69 - subdir: 'bundled' - url: 'https://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.xz' - format: 'tar.xz' - extract_path: 'autoconf-2.69' - patch-path-strip: 3 - version: '2.69' - configure: - - args: ['@THIS_SOURCE_DIR@/configure', '--prefix=@PREFIX@'] - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install'] - - - name: host-automake-v1.16 - source: - name: automake-v1.16 - subdir: 'bundled' - git: 'https://github.com/autotools-mirror/automake' - tag: 'v1.16.5' - version: '1.16.5' - tools_required: - - host-autoconf-v2.69 - regenerate: - - args: ['./bootstrap'] - tools_required: - - host-autoconf-v2.69 - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: | - set -e - export PATH="`pwd`/bin:$PATH" - make bin/aclocal-1.16 bin/automake-1.16 -j@PARALLELISM@ - make -j@PARALLELISM@ - install: - - args: ['make', 'install-strip'] - - args: ['ln', '-sf', '@PREFIX@/share/aclocal-1.16', '@PREFIX@/share/aclocal'] - - - name: host-rust - from_source: rust - tools_required: - - host-llvm - sources_required: - - rust-patched-libs - compile: - - args: | - cat << EOF > config.toml - changelog-seen = 2 - - [llvm] - targets = "X86" - - [build] - target = ["x86_64-unknown-aero-system", "x86_64-unknown-linux-gnu"] - build-dir = "@THIS_BUILD_DIR@" - docs = false - - [install] - prefix = "@PREFIX@" - - [rust] - codegen-tests = false - deny-warnings = false # work around rust-num-cpus warning - - [target.x86_64-unknown-linux-gnu] - llvm-config = "@BUILD_ROOT@/tools/host-llvm/bin/llvm-config" - - [target.x86_64-unknown-aero-system] - llvm-config = "@BUILD_ROOT@/tools/host-llvm/bin/llvm-config" - EOF - - args: ['python3', '@THIS_SOURCE_DIR@/x.py', 'build', '--stage', '2', '-j', '@PARALLELISM@'] - install: - - args: ['python3', '@THIS_SOURCE_DIR@/x.py', 'install', '-j', '@PARALLELISM@'] - - - name: host-cargo - source: - subdir: 'bundled' - git: 'https://github.com/rust-lang/cargo.git' - branch: 'master' - commit: '25fcb135d02ea897ce894b67ae021f48107d522b' - tools_required: - - tool: host-rust - recursive: true - - tool: host-gcc # GCC is used for linking - recursive: true - sources_required: - # This cargo runs on the host, so we don't actually need any patches here. We just - # add the sources used by cargo so that the dependency resolver doesn't complain. - - rust-patched-libs - compile: - - args: - - 'cargo' - - 'install' - - '--target' - - 'x86_64-unknown-linux-gnu' - - '--target-dir' - - '@THIS_BUILD_DIR@' - - '--path' - - '@THIS_SOURCE_DIR@' - - '-j@PARALLELISM@' - - '--root' - - '@PREFIX@' - - - name: host-python - from_source: python - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install'] - - - name: host-binutils - from_source: binutils - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - - '--target=x86_64-aero' - - '--with-sysroot=@SYSROOT_DIR@' - # On recent compilers, binutils 2.26 causes implicit-fallthrough warnings, among others. - - '--disable-werror' - - '--enable-targets=x86_64-elf,x86_64-pe' - # -g blows up the binary size. - - 'CFLAGS=-pipe' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install'] - - - name: host-gcc - from_source: gcc - tools_required: - - tool: host-binutils - recursive: true - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - - '--target=x86_64-aero' - - '--with-sysroot=@SYSROOT_DIR@' - - '--enable-languages=c,c++' - - '--disable-multilib' - - '--enable-initfini-array' - # -g blows up GCC's binary size. - - 'CFLAGS=-O2 -pipe' - - 'CXXFLAGS=-O2 -pipe' - stages: - - name: compiler - pkgs_required: - - mlibc-headers - compile: - - args: ['make', '-j@PARALLELISM@', 'all-gcc'] - install: - - args: ['make', 'install-gcc'] - # GCC does *not* look for target-prefixed LD/AS. - # Instead, it searches a list of prefix directories. Link AS/LD to make it happy. - - args: ['mkdir', '-p', '@PREFIX@/x86_64-aero/bin'] - - args: ['ln', '-sf', '../../../host-binutils/x86_64-aero/bin/as', - '@PREFIX@/x86_64-aero/bin/as'] - - args: ['ln', '-sf', '../../../host-binutils/x86_64-aero/bin/ld', - '@PREFIX@/x86_64-aero/bin/ld'] - - name: libgcc - tools_required: - - tool: host-gcc - stage_dependencies: [compiler] - pkgs_required: - - mlibc - compile: - - args: ['make', '-j@PARALLELISM@', 'all-target-libgcc'] - install: - - args: ['make', 'install-strip-target-libgcc'] - - - name: libstdc++ - tools_required: - - tool: host-gcc - stage_dependencies: [libgcc] - compile: - - args: ['make', '-j@PARALLELISM@', 'all-target-libstdc++-v3'] - install: - - args: ['make', 'install-strip-target-libstdc++-v3'] - - - name: host-llvm - from_source: llvm - sources_required: - - binutils - configure: - - args: - - 'cmake' - - '-GNinja' - - '-DCMAKE_INSTALL_PREFIX=@PREFIX@' - # LLVM configuration options. - # We really have to build LLVM in Release mode. - # Building it in debug mode produces tens of GiB of debugging info. - - '-DCMAKE_BUILD_TYPE=Release' - - '-DLLVM_TARGETS_TO_BUILD=X86' - - '-DLLVM_ENABLE_PROJECTS=llvm' - - '-DLLVM_ENABLE_Z3_SOLVER=OFF' - # clang configuration options. - - '-DDEFAULT_SYSROOT=@SYSROOT_DIR@' - # Gold linker configuration options. - - '-DLLVM_BINUTILS_INCDIR=@SOURCE_ROOT@/bundled/binutils/include' - - '@THIS_SOURCE_DIR@/llvm' - compile: - - args: ['ninja', '-j@PARALLELISM@'] - # Build on a single CPU to prevent OOM on smaller systems. - #- args: ['ninja', '-j1'] - install: - - args: ['ninja', 'install', '-j@PARALLELISM@'] - # quiet: true - - - name: host-libtool - exports_aclocal: true - source: - name: libtool - subdir: 'bundled' - git: 'https://git.savannah.gnu.org/git/libtool.git' - tag: 'v2.4.6' - version: '2.4.6' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - regenerate: - # libtool's ./bootstrap does a shallow clone with insufficient depth. - - args: ['git', 'submodule', 'update', '--init'] - - args: ['./bootstrap'] - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install'] - - - name: wayland-scanner - from_source: wayland - tools_required: - - virtual: pkgconfig-for-host - program_name: host-pkg-config - configure: - - args: - - 'meson' - - '--native-file' - - '@SOURCE_ROOT@/userland/native-file.ini' - - '--prefix=@PREFIX@' - - '-Ddtd_validation=false' - - '-Ddocumentation=false' - - '-Dscanner=true' - - '-Dlibraries=false' - - '@THIS_SOURCE_DIR@' - compile: - - args: ['ninja'] - install: - - args: ['ninja', 'install'] - -packages: - - name: ripgrep - source: - subdir: bundled - git: 'https://github.com/BurntSushi/ripgrep.git' - tag: '12.1.1' - version: '12.1.1' - tools_required: - - host-cargo - sources_required: - - rust-patched-libs - pkgs_required: - - mlibc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - # cc: https://github.com/rust-lang/cargo/issues/10283 - # - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', '@THIS_SOURCE_DIR@/Cargo.toml'] - build: - - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', './Cargo.toml'] - - args: - - 'cargo' - - 'install' - - '--locked' - - '--path' - - '.' - - '--root' - - '@THIS_COLLECT_DIR@/usr' - - '-j@PARALLELISM@' - - - name: hex - source: - subdir: bundled - git: 'https://github.com/sitkevij/hex' - tag: 'v0.4.2' - version: '0.4.2' - tools_required: - - host-cargo - sources_required: - - rust-patched-libs - pkgs_required: - - mlibc - configure: - # cc: https://github.com/rust-lang/cargo/issues/10283 - # - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', '@THIS_SOURCE_DIR@/Cargo.toml'] - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - build: - - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', './Cargo.toml'] - - args: - - 'cargo' - - 'install' - - '--locked' - - '--path' - - '.' - - '--root' - - '@THIS_COLLECT_DIR@/usr' - - '-j@PARALLELISM@' - - # - name: bat - # source: - # subdir: 'bundled' - # git: 'https://github.com/sharkdp/bat' - # branch: master - # commit: '7334ab45422882686212ed31df2d95c02e7585f1' - # tools_required: - # - host-cargo - # sources_required: - # - rust-patched-libs - # pkgs_required: - # - mlibc - # configure: - # - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - # build: - # - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', './Cargo.toml'] - # - args: - # - 'cargo' - # - 'install' - # - '--locked' - # - '--path' - # - '.' - # - '--root' - # - '@THIS_COLLECT_DIR@/usr' - # - '-j@PARALLELISM@' - # - '--no-default-features' - # - '--features=regex-fancy,wild,clap,atty,dirs-next,paging' - - - name: quickjs - source: - subdir: bundled - git: 'https://github.com/bellard/quickjs' - branch: master - commit: 'b5e62895c619d4ffc75c9d822c8d85f1ece77e5b' - tools_required: - - host-gcc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - build: - - args: ['make', '-j@PARALLELISM@', 'CROSS_PREFIX=x86_64-aero-'] - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/usr/bin'] - - args: ['cp', '@THIS_BUILD_DIR@/qjs', '@THIS_COLLECT_DIR@/usr/bin/qjs'] - - - name: sd - source: - subdir: bundled - git: 'https://github.com/chmln/sd' - tag: 'v0.7.6' - version: '0.7.6' - tools_required: - - host-cargo - sources_required: - - rust-patched-libs - pkgs_required: - - mlibc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - # cc: https://github.com/rust-lang/cargo/issues/10283 - # - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', '@THIS_SOURCE_DIR@/Cargo.toml'] - build: - - args: ['python3', '@SOURCE_ROOT@/tools/cargo-inject-patches.py', './Cargo.toml'] - - args: - - 'cargo' - - 'install' - - '--locked' - - '--path' - - '.' - - '--root' - - '@THIS_COLLECT_DIR@/usr' - - '-j@PARALLELISM@' - - - name: mlibc-headers - from_source: mlibc - implict_package: true - configure: - - args: - - 'meson' - - '--cross-file' - - '@SOURCE_ROOT@/userland/cross-file.ini' - - '--prefix=/usr' - - '-Dheaders_only=true' - - '-Ddisable_iconv_option=true' - - '-Dbuildtype=debug' - - '@THIS_SOURCE_DIR@' - build: - - args: ['ninja'] - - args: ['ninja', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: mlibc - from_source: mlibc - tools_required: - - tool: host-gcc - stage_dependencies: [compiler] - implict_package: true - pkgs_required: - - mlibc-headers - configure: - - args: - - 'meson' - - '--cross-file' - - '@SOURCE_ROOT@/userland/cross-file.ini' - - '--prefix=/usr' - - '--libdir=lib' - - '-Dmlibc_no_headers=true' - - '-Ddisable_iconv_option=true' - - '-Dbuildtype=debug' - - '@THIS_SOURCE_DIR@' - build: - - args: ['ninja'] - - args: ['ninja', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libdrm - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/mesa/drm' - tag: 'libdrm-2.4.110' - version: '2.4.110' - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: - - 'meson' - - '--cross-file' - - '@SOURCE_ROOT@/userland/cross-file.ini' - - '--prefix=/usr' - - '--libdir=lib' - - '--buildtype=debugoptimized' - - '-Dintel=false' - - '-Dvmwgfx=false' - - '-Dradeon=false' - - '-Damdgpu=false' - - '-Dnouveau=false' - - '-Dman-pages=false' - # We might want to build cairo with OpenGL support. - # Doing so would introduce a circular dependency here. - - '-Dcairo-tests=false' - - '@THIS_SOURCE_DIR@' - build: - - args: ['ninja'] - - args: ['ninja', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: drm_test - source: - subdir: 'bundled' - # copied from https://github.com/dvdhrm/docs/tree/master/drm-howto - # - # changes: compile to the aero target instead of the linux one. - git: 'https://github.com/aero-os/drm_test' - branch: 'master' - tools_required: - - host-gcc - pkgs_required: - - libdrm - - mlibc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - build: - - args: ['make'] - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/usr/bin'] - - args: ['mv', 'drm', '@THIS_COLLECT_DIR@/usr/bin'] - - - name: nyancat - source: - subdir: 'bundled' - git: 'https://github.com/klange/nyancat.git' - tag: '1.5.2' - version: '1.5.2' - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - build: - - args: ['make', '-j@PARALLELISM@'] - environ: - CC: "x86_64-aero-gcc" - - args: ['mkdir', '-pv', '@THIS_COLLECT_DIR@/usr/bin'] - - args: ['mkdir', '-pv', '@THIS_COLLECT_DIR@/usr/share/man/man1'] - - args: ['cp', '-v', '@THIS_BUILD_DIR@/src/nyancat', '@THIS_COLLECT_DIR@/usr/bin'] - - args: ['cp', '-v', '@THIS_BUILD_DIR@/nyancat.1', '@THIS_COLLECT_DIR@/usr/share/man/man1'] - - - name: coreutils - source: - subdir: 'bundled' - url: 'https://ftp.gnu.org/gnu/coreutils/coreutils-8.32.tar.xz' - format: 'tar.xz' - extract_path: 'coreutils-8.32' - patch-path-strip: 3 - tools_required: - - host-gcc - configure: - # Huge hack: coreutils does not compile the build-machine binary make-prime-list - # using the build-machine compiler. Hence, build and invoke the binary manually here. - - args: - - '@THIS_SOURCE_DIR@/configure' - - args: ['make', 'src/make-prime-list'] - - args: | - ./src/make-prime-list 5000 > @THIS_SOURCE_DIR@/src/primes.h - - args: ['make', 'clean'] - # No compile coreutils for the correct target. - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - 'CFLAGS=-DSLOW_BUT_NO_HACKS -Wno-error' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: tzdata - from_source: tzdata - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@/'] - build: - # Build and install support programs - - args: ['make', 'CC=x86_64-aero-gcc', 'AR=x86_64-aero-ar'] - - args: ['make', 'install', 'DESTDIR=@THIS_COLLECT_DIR@', 'ZIC=zic'] - # Create the required directories - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/etc'] - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/usr/share/zoneinfo/posix'] - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/usr/share/zoneinfo/right'] - # Create the time zone files without leap seconds, convention puts these in both zoneinfo and zoneinfo/posix. - # After that. create time time zone files with leap seconds - - args: | - set -e - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/etcetera - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/etcetera - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/etcetera - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/southamerica - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/southamerica - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/southamerica - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/northamerica - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/northamerica - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/northamerica - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/europe - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/europe - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/europe - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/africa - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/africa - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/africa - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/antarctica - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/antarctica - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/antarctica - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/asia - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/asia - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/asia - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/australasia - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/australasia - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/australasia - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo "@THIS_BUILD_DIR@"/backward - zic -L /dev/null -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/posix "@THIS_BUILD_DIR@"/backward - zic -L "@THIS_SOURCE_DIR@"/leapseconds -d "@THIS_COLLECT_DIR@"/usr/share/zoneinfo/right "@THIS_BUILD_DIR@"/backward - # Create the posixrules file, POSIX requires daylight saving rules to be in accordance with US rules, thus use New York - - args: ['zic', '-d', '@THIS_COLLECT_DIR@/usr/share/zoneinfo', '-p', 'America/New_York'] - # Default to UTC for localtime, this should be fixed, but that is pending xbstrap support. - - args: ['ln', '-sf', '/usr/share/zoneinfo/UTC', '@THIS_COLLECT_DIR@/etc/localtime'] - - - name: gcc - from_source: gcc - revision: 2 - tools_required: - - host-gcc - pkgs_required: - - mlibc - - binutils - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--target=x86_64-aero' - - '--with-sysroot=/' - - '--with-build-sysroot=@SYSROOT_DIR@' - - '--enable-languages=c,c++' - - '--enable-initfini-array' - - '--disable-multilib' - - '--disable-nls' - # -g blows up GCC's binary size. - - 'CFLAGS=-O2 -pipe' - - 'CXXFLAGS=-O2 -pipe' - build: - - args: ['make', '-j@PARALLELISM@', 'all-gcc', 'all-target-libgcc'] - - args: ['make', 'install-strip-gcc', 'install-strip-target-libgcc'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - args: ['sh', '-c', 'cp -rv @BUILD_ROOT@/tools/host-gcc/x86_64-aero/lib/* @THIS_COLLECT_DIR@/usr/lib/'] - - args: ['sh', '-c', 'cp -rv @BUILD_ROOT@/tools/host-gcc/x86_64-aero/include/* @THIS_COLLECT_DIR@/usr/include/'] - - args: ['ln', '-s', '/usr/bin/gcc', '@THIS_COLLECT_DIR@/usr/bin/cc'] - - - name: binutils - from_source: binutils - tools_required: - - host-gcc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--target=x86_64-aero' - - '--with-sysroot=/' - - '--disable-nls' - # On recent compilers, binutils 2.26 causes implicit-fallthrough warnings, among others. - - '--disable-werror' - - '--disable-gdb' - # -g blows up the binary size. - - 'CFLAGS=-pipe' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: bash - source: - git: 'https://github.com/bminor/bash' - # Checkout bash 5.1 - branch: 'master' - commit: '9439ce094c9aa7557a9d53ac7b412a23aa66e36b' - version: '5.1.16' - subdir: 'bundled' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--without-bash-malloc' - - '--disable-nls' - environ: - ac_cv_func_wcswidth: 'no' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'DESTDIR=@THIS_COLLECT_DIR@', 'install'] - - - name: tcc - source: - subdir: 'bundled' - git: 'https://github.com/aero-os/tcc' - branch: master - patch-path-strip: 3 - tools_required: - - host-gcc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--tccdir=/usr/lib/tcc' - - '--elfinterp=/usr/lib/ld.so' - - '--libpaths=/usr/lib' - - '--sysincludepaths=/usr/lib/tcc/include:/usr/include' - - '--cross-prefix=x86_64-aero-' - - '--cc=gcc' - - '--ar=ar' - - '--with-selinux' - - '--strip-binaries' - - '--prefix=/usr' - build: - - args: ['make'] - - args: ['make', 'DESTDIR=@THIS_COLLECT_DIR@', 'install-strip'] - - - name: nasm - source: - subdir: 'bundled' - url: 'http://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.xz' - format: 'tar.xz' - extract_path: 'nasm-2.14.02' - version: '2.14.02' - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - 'CFLAGS=-g -O0' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: python - from_source: python - tools_required: - - host-gcc - - host-python - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--build=x86_64-linux-gnu' - - '--prefix=/usr' - - '--enable-shared' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - - '--with-system-ffi' - - '--with-system-expat' - - '--disable-ipv6' - - '--without-ensurepip' - environ: - CONFIG_SITE: '@SOURCE_ROOT@/extra-files/python/python-config-site' - PKG_CONFIG_SYSROOT_DIR: '@BUILD_ROOT@/system-root' - PKG_CONFIG_LIBDIR: '@BUILD_ROOT@/system-root/usr/lib/pkgconfig:@BUILD_ROOT@/system-root/usr/share/pkgconfig' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: doomgeneric - source: - subdir: 'bundled' - git: 'https://github.com/ozkl/doomgeneric.git' - branch: 'master' - commit: '2d9b24f07c78c36becf41d89db30fa99863463e5' - tools_required: - - host-gcc - pkgs_required: - - mlibc - build: - - args: ['make', '-C', '@THIS_SOURCE_DIR@/doomgeneric', '-f', 'Makefile.aero', '-j@PARALLELISM@'] - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/usr/bin'] - - args: ['cp', '@THIS_SOURCE_DIR@/doomgeneric/doomgeneric', '@THIS_COLLECT_DIR@/usr/bin/doomgeneric'] - - - name: lua - source: - subdir: bundled - url: 'https://www.lua.org/ftp/lua-5.3.5.tar.gz' - format: 'tar.gz' - extract_path: 'lua-5.3.5' - version: '5.3.5' - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: ['cp', '-r', '@THIS_SOURCE_DIR@/.', '@THIS_BUILD_DIR@'] - - args: - - 'sed' - - '-i' - - 's|^#define LUA_ROOT "/usr/local/"$|#define LUA_ROOT "/usr/"|' - - 'src/luaconf.h' - build: - - args: - - 'make' - - 'generic' - - 'CC=x86_64-aero-gcc' - - 'AR=x86_64-aero-ar rcu' - - 'RANLIB=x86_64-aero-ranlib' - - '-j@PARALLELISM@' - - args: ['make', 'install', 'INSTALL_TOP=@THIS_COLLECT_DIR@/usr'] - - # -------------------- wayland -------------------- - - name: wayland-protocols - source: - subdir: 'bundled' - git: 'https://github.com/wayland-project/wayland-protocols.git' - tag: '1.24' - version: '1.24' - tools_required: - - host-gcc - - wayland-scanner - configure: - - args: - - 'meson' - - '--cross-file' - - '@SOURCE_ROOT@/userland/cross-file.ini' - - '--prefix=/usr' - - '--buildtype=release' - - '-Dtests=false' - - '@THIS_SOURCE_DIR@' - build: - - args: ['ninja'] - - args: ['ninja', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - quiet: true - - - name: libexpat - source: - subdir: 'bundled' - git: 'https://github.com/libexpat/libexpat.git' - tag: 'R_2_4_1' - version: '2.4.1' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - regenerate: - - args: ['./buildconf.sh'] - workdir: '@THIS_SOURCE_DIR@/expat' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-gcc - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/expat/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - # We disable xmlwf to avoid building its documentation. - - '--without-xmlwf' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - quiet: true - - - name: libffi - source: - subdir: 'bundled' - git: 'https://github.com/libffi/libffi.git' - tag: 'v3.4.2' - version: '3.4.2' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - regenerate: - - args: ['./autogen.sh'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/'] - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: wayland - from_source: wayland - tools_required: - - host-pkg-config - - host-gcc - - wayland-scanner - - host-libtool - - virtual: pkgconfig-for-target - triple: "x86_64-aero" - - virtual: pkgconfig-for-host - program_name: host-pkg-config - pkgs_required: - - mlibc - - libexpat - - libffi - configure: - - args: - - 'meson' - - '--native-file' - - '@SOURCE_ROOT@/userland/native-file.ini' - - '--cross-file' - - '@SOURCE_ROOT@/userland/cross-file.ini' - - '--prefix=/usr' - - '--buildtype=debugoptimized' - - '-Ddtd_validation=false' - - '-Ddocumentation=false' - - '-Dscanner=false' - - '@THIS_SOURCE_DIR@' - environ: - PKG_CONFIG_SYSROOT_DIR: '@BUILD_ROOT@/system-root' - build: - - args: ['ninja'] - - args: ['ninja', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: zlib - source: - subdir: 'bundled' - git: 'https://github.com/madler/zlib.git' - tag: 'v1.2.12' - version: '1.2.12' - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - environ: - CHOST: 'x86_64-aero' - prefix: '/usr' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: openssl - source: - subdir: 'bundled' - git: 'https://github.com/openssl/openssl.git' - tag: 'OpenSSL_1_1_1o' - version: '1.1.1o' - tools_required: - - host-gcc - pkgs_required: - - mlibc - - zlib - configure: - - args: - - '@THIS_SOURCE_DIR@/Configure' - - '--prefix=/usr' - - '--openssldir=/etc/ssl' - - '--libdir=lib' - - 'x86_64-aero' - - 'shared' - - 'zlib-dynamic' - - 'no-afalgeng' - environ: - CC: 'x86_64-aero-gcc' - CXX: 'x86_64-aero-g++' - build: - - args: ['make', '-j@PARALLELISM@'] - # Disable installing static libraries - - args: ['sed', '-i', '/INSTALL_LIBS/s/libcrypto.a libssl.a//', '@THIS_BUILD_DIR@/Makefile'] - # Suffix all man pages with ssl - - args: ['make', 'DESTDIR=@THIS_COLLECT_DIR@', 'MANSUFFIX=ssl', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - # Move the doc dir to a versioned directory - - args: ['mv', '@THIS_COLLECT_DIR@/usr/share/doc/openssl', '@THIS_COLLECT_DIR@/usr/share/doc/openssl-1.1.1o'] - - - name: libpng - source: - subdir: 'bundled' - git: 'https://git.code.sf.net/p/libpng/code' - tag: 'v1.6.37' - version: '1.6.37' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - regenerate: - - args: ['git', 'clean', '-xf', '-e', '*.xbstrap'] - - args: ['autoreconf', '-fvi'] - tools_required: - - host-gcc - pkgs_required: - - mlibc - - zlib - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: freetype - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/freetype/freetype.git' - tag: 'VER-2-12-1' - version: '2.12.1' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: '1' - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/builds/unix/'] - tools_required: - - host-gcc - pkgs_required: - - mlibc - - libpng - - zlib - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--disable-static' - - '--with-harfbuzz=no' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: fontconfig - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/fontconfig/fontconfig.git' - tag: '2.14.0' - version: '2.14.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - # Make sure we regenerate this file - - args: ['rm', '-f', 'src/fcobjshash.h'] - pkgs_required: - - mlibc - - freetype - - libxml - - libiconv - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-gcc - - host-libtool - - host-pkg-config - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-docs' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - - '--enable-libxml2' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libxml - source: - subdir: 'bundled' - git: 'https://gitlab.gnome.org/GNOME/libxml2.git' - tag: 'v2.9.14' - version: '2.9.14' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - pkgs_required: - - mlibc - - zlib - - python - - libiconv - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-python=@SYSROOT_DIR@/usr/bin/python3.8' - - '--disable-static' - - '--with-threads' - - '--disable-ipv6' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libiconv - source: - subdir: 'bundled' - git: 'https://git.savannah.gnu.org/git/libiconv.git' - # Last release tag is broken for us, use current master (07-12-2020) - branch: 'master' - commit: '0eb1068ceb77ba383c3ce2fc391ab40ef686c491' - version: '1.16' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./gitsub.sh', 'pull'] - # Gnulib broke on commit e3174b6d1fdbe6ea2297bf8c8333f65f9d9d9588, so check out the one before that. - - args: ['git', 'checkout', '766ec17a90f67e8cda78394e58a7fffb00f5a4b7'] - workdir: '@THIS_SOURCE_DIR@/gnulib' - - args: ['./autogen.sh'] - environ: - 'NOCONFIGURE': 'yes' - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/build-aux/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-automake-v1.16/share/automake-1.16/config.sub', - '@THIS_SOURCE_DIR@/libcharset/build-aux/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-libtool/share/aclocal/libtool.m4', - '@THIS_SOURCE_DIR@/m4/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-libtool/share/aclocal/libtool.m4', - '@THIS_SOURCE_DIR@/libcharset/m4/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-libtool/share/libtool/build-aux/ltmain.sh', - '@THIS_SOURCE_DIR@/libcharset/build-aux/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-libtool/share/libtool/build-aux/ltmain.sh', - '@THIS_SOURCE_DIR@/build-aux/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-libtool/share/aclocal/ltversion.m4', - '@THIS_SOURCE_DIR@/m4/'] - - args: ['cp', - '@BUILD_ROOT@/tools/host-libtool/share/aclocal/ltversion.m4', - '@THIS_SOURCE_DIR@/libcharset/m4/'] - - args: ['autoreconf', '-fvi', '-I@THIS_SOURCE_DIR@/m4', '-I@THIS_SOURCE_DIR@/srcm4'] - tools_required: - - host-gcc - - host-libtool - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - - '--disable-nls' - - '--enable-shared' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # - name: weston - # labels: [aarch64] - # architecture: '@OPTION:arch@' - # source: - # subdir: 'ports' - # git: 'https://github.com/wayland-project/weston.git' - # tag: '10.0.0' - # version: '10.0.0' - # tools_required: - # - host-autoconf-v2.69 - # - host-automake-v1.16 - # - host-libtool - # - host-pkg-config - # - system-gcc - # - wayland-scanner - # - virtual: pkgconfig-for-target - # triple: "@OPTION:arch-triple@" - # - virtual: pkgconfig-for-host - # program_name: host-pkg-config - # pkgs_required: - # - mlibc - # - cairo - # - libinput - # - libxkbcommon - # - mesa - # - wayland - # - wayland-protocols - # - dejavu - # - libxcursor - # - xorg-server - # - pango - # - glib - # - libjpeg-turbo - # configure: - # - args: - # - 'meson' - # - '--native-file' - # - '@SOURCE_ROOT@/scripts/meson.native-file' - # - '--cross-file' - # - '@SOURCE_ROOT@/scripts/meson-@OPTION:arch-triple@.cross-file' - # - '--prefix=/usr' - # - '--libdir=lib' - # - '--buildtype=debugoptimized' - # - '-Dbackend-x11=false' - # - '-Dsimple-clients=damage,im,egl,shm,touch' - # - '-Dimage-jpeg=true' - # - '-Dimage-webp=false' - # - '-Dlauncher-logind=false' - # - '-Dbackend-drm-screencast-vaapi=false' - # - '-Dbackend-rdp=false' - # - '-Dcolor-management-colord=false' - # - '-Dcolor-management-lcms=false' - # - '-Dsystemd=false' - # - '-Dremoting=false' - # - '-Dpipewire=false' - # - '@THIS_SOURCE_DIR@' - # environ: - # PKG_CONFIG_SYSROOT_DIR: '@BUILD_ROOT@/system-root' - # PKG_CONFIG_LIBDIR: '@BUILD_ROOT@/system-root/usr/lib/pkgconfig:@BUILD_ROOT@/system-root/usr/share/pkgconfig' - # build: - # - args: ['ninja'] - # - args: ['ninja', 'install'] - # environ: - # DESTDIR: '@THIS_COLLECT_DIR@' - # quiet: true - -tasks: - - name: sysroot - pkgs_required: - - binutils - - coreutils - - nyancat - - gcc - - tcc - args: - - '@SOURCE_ROOT@/make-iso.sh' - - '@BUILD_ROOT@' - - '@SOURCE_ROOT@' - - '@SYSROOT_DIR@' - workdir: '@BUILD_ROOT@' diff --git a/bootstrap/xorg.yml b/bootstrap/xorg.yml deleted file mode 100644 index d096c5bb9fe..00000000000 --- a/bootstrap/xorg.yml +++ /dev/null @@ -1,1548 +0,0 @@ -sources: - - name: xorg-util-macros - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/util/macros.git' - tag: 'util-macros-1.19.3' - version: '1.19.3' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - - - name: xorg-font-util - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/font/util.git' - tag: 'font-util-1.3.2' - version: '1.3.2' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - - - name: gettext - subdir: 'bundled' - git: 'https://git.savannah.gnu.org/git/gettext.git' - tag: 'v0.19.8' - version: '0.19.8' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - -tools: - - name: host-xorg-macros - exports_aclocal: true - from_source: xorg-util-macros - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install-strip'] - - - name: host-xtrans - exports_aclocal: true - from_source: libxtrans - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install-strip'] - - - name: host-xorg-font-util - exports_aclocal: true - from_source: xorg-font-util - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: ['make', '-j@PARALLELISM@'] - install: - - args: ['make', 'install-strip'] - - - name: host-gettext - from_source: gettext - exports_aclocal: true - tools_required: - # - host-bison - - host-autoconf-v2.69 - - host-automake-v1.16 - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--prefix=@PREFIX@' - compile: - - args: ['make'] - install: - - args: ['make', 'install-strip'] - -packages: - # `xorg-util-macros` is a set of autoconf macros used by the configure.ac scripts in - # other Xorg modular packages, and is needed to generate new versions - # of their configure scripts with autoconf. - - name: xorg-util-macros - from_source: xorg-util-macros - tools_required: - - host-gcc - - host-xorg-macros - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `xorg-proto` provides the headers and specification documents defining the core protocol - # and extensions for the X Window System. - - name: xorg-proto - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/proto/xorgproto.git' - tag: 'xorgproto-2022.1' - version: '2022.1' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `xcb-proto` provides the XML-XCB protocol descriptions that libxcb uses to - # generate the majority of its code and API. - - name: xcb-proto - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/proto/xcbproto.git' - tag: 'xcb-proto-1.15' - version: '1.15' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-python - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libxau - - libxdmcp - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - environ: - PYTHON: '@BUILD_ROOT@/tools/host-python/bin/python3.8' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxdmcp` is X Display Manager Control Protocol library. - - name: libxdmcp - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxdmcp.git' - tag: 'libXdmcp-1.1.3' - version: '1.1.3' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libxau - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `xtrans` is a library of code that is shared among various X packages to - # handle network protocol transport in a modular fashion. - - name: libxtrans - from_source: libxtrans - tools_required: - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libxcb - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxau` is a sample authorization protocol for X - - name: libxau - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxau.git' - tag: 'libXau-1.0.9' - version: '1.0.9' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxcb` provides an interface to the X Window System protocol, which - # replaces the traditional Xlib interface. - - name: libxcb - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxcb.git' - tag: 'libxcb-1.15' - version: '1.15' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-python - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libxau - - libxdmcp - - xcb-proto - configure: - - args: ['sed', '-i', "s/pthread-stubs//", '@THIS_SOURCE_DIR@/configure'] - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--without-doxygen' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - environ: - CFLAGS: '-g -O0' - PYTHON: '@BUILD_ROOT@/tools/host-python/bin/python3.8' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libx11` is core X11 protocol client library. - - name: libx11 - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libx11.git' - tag: 'libX11-1.8' - version: '1.8' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xtrans - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libxcb - - libxtrans - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-ipv6' - - '--disable-malloc0returnsnull' - - '--with-keysymdefdir=@SYSROOT_DIR@/usr/include/X11' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxkbfile` is used by the X servers and utilities to parse the XKB - # configuration data files. - - name: libxkbfile - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxkbfile.git' - tag: 'libxkbfile-1.1.0' - version: '1.1.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: xorg-font-util - from_source: xorg-font-util - tools_required: - - host-gcc - pkgs_required: - - mlibc - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libfontenc` is a font encoding library. - - name: libfontenc - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libfontenc.git' - tag: 'libfontenc-1.1.4' - version: '1.1.4' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xorg-font-util - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - - xorg-font-util - - zlib - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxfont` provides the core of the legacy X11 font system, handling the index - # files - - name: libxfont2 - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxfont.git' - tag: 'libXfont2-2.0.5' - version: '2.0.5' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xtrans - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-xtrans - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - - freetype - - libfontenc - - fontconfig - - zlib - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-devel-docs' - # strcasecmp is implicitly declared, probably an missing include somewhere, so disable -Werror for that - - '--disable-selective-werror' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `pixman` is a library that provides low-level pixel manipulation - # features such as image compositing and trapezoid rasterization. - - name: pixman - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/pixman/pixman.git' - tag: 'pixman-0.40.0' - version: '0.40.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - regenerate: - - args: ['./autogen.sh'] - environ: - 'NOCONFIGURE': 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - libpng - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # The X server accepts requests from client applications to create windows, - # which are (normally rectangular) "virtual screens" that the client program - # can draw into. - - name: xorg-server - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/xserver.git' - tag: 'xorg-server-1.20.14' - version: '1.20.14' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xorg-font-util - - host-xtrans - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - openssl - - libxkbfile - - libxfont2 - - pixman - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - - '--with-xkb-output=/var/lib/xkb' - - '--enable-xorg' - - '--enable-xv' - - '--enable-xvfb' - - '--disable-xephyr' - - '--disable-xwayland' - - '--disable-xnest' - - '--disable-dmx' - - '--disable-suid-wrapper' - - '--disable-pciaccess' - - '--disable-dpms' - - '--disable-screensaver' - - '--disable-xres' - - '--disable-xinerama' - - '--disable-xvmc' - - '--disable-systemd-logind' - - '--disable-secure-rpc' - - '--disable-config-udev' - - '--disable-dri' - - '--disable-dri2' - - '--disable-dri3' - - '--disable-vbe' - - '--disable-int10-module' - - '--disable-vgahw' - - '--disable-libdrm' - - '--disable-glamor' - - '--disable-glx' - environ: - CFLAGS: '-Wno-error=array-bounds -O0 -g -pipe' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - args: ['mkdir', '-p', '@THIS_COLLECT_DIR@/etc/X11'] - - args: ['cp', '@SOURCE_ROOT@/extra-files/xorg/xorg.conf', '@THIS_COLLECT_DIR@/etc/X11/'] - - # `libxext` is the historical libX11-based catchall library for the X11 - # extensions without their own libraries. - - name: libxext - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxext.git' - tag: 'libXext-1.3.4' - version: '1.3.4' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-malloc0returnsnull' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libsm` is a X session management library. - - name: libsm - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libsm.git' - tag: 'libSM-1.2.3' - version: '1.2.3' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xtrans - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-gcc - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - - libice - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libxt - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxt.git' - tag: 'libXt-1.2.1' - version: '1.2.1' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - - libsm - - libice - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-malloc0returnsnull' - - '--with-appdefaultdir=/etc/X11/app-defaults' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxmu` contains miscellaneous utilities and is not part of the Xlib - # standard - - name: libxmu - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxmu.git' - tag: 'libXmu-1.1.3' - version: '1.1.3' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xtrans - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxext - - libxtrans - - libxt - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libice` is a inter-client exchange library. - - name: libice - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libice.git' - tag: 'libICE-1.0.10' - version: '1.0.10' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-xtrans - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxaw` is the X athena widget set. - - name: libxaw - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxaw.git' - tag: 'libXaw-1.0.14' - version: '1.0.14' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxext - - libxt - - libxmu - - libxpm - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxpm` is X Pixmap (XPM) image file format library. - - name: libxpm - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxpm.git' - tag: 'libXpm-3.5.13' - version: '3.5.13' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxext - - libxt - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxrender` is a library for the Render Extension to the X11 protocol - - name: libxrender - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxrender.git' - tag: 'libXrender-0.9.10' - version: '0.9.10' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-malloc0returnsnull' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxft` is X FreeType library. - - name: libxft - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxft.git' - tag: 'libXft-2.3.4' - version: '2.3.4' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxrender - - freetype - - fontconfig - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxi` is library for the X input extension. - - name: libxi - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxi.git' - tag: 'libXi-1.8' - version: '1.8' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - - libxext - - libxfixes - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-malloc0returnsnull' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `libxfixes` is xfixes extension library. - - name: libxfixes - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxfixes.git' - tag: 'libXfixes-6.0.0' - version: '6.0.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - # `xeyes` is a follow the mouse X demo, using the X shape extension. - - name: xeyes - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/app/xeyes.git' - tag: 'xeyes-1.2.0' - version: '1.2.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-gettext - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - libx11 - - libxmu - - libxaw - - libxrender - - libxft - - libxt - - libxkbfile - - libiconv - - libxi - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-selective-werror' # strncasecmp - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libxv - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxv.git' - tag: 'libXv-1.0.11' - version: '1.0.11' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxext - - libxfixes - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-malloc0returnsnull' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libxrandr - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/lib/libxrandr.git' - tag: 'libXrandr-1.5.2' - version: '1.5.2' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxtrans - - libxrender - - libxext - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--disable-malloc0returnsnull' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: xkbcomp - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/app/xkbcomp.git' - tag: 'xkbcomp-1.4.5' - version: '1.4.5' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-util-macros - - libx11 - - libxkbfile - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: libxkbcommon - source: - subdir: 'bundled' - git: 'https://github.com/xkbcommon/libxkbcommon.git' - tag: 'xkbcommon-1.4.0' - version: '1.4.0' - tools_required: - - host-pkg-config - - host-gcc - - virtual: pkgconfig-for-host - program_name: host-pkg-config - - virtual: pkgconfig-for-target - triple: "x86_64-aero" - pkgs_required: - - mlibc - - libxcb - - libxml - - xkeyboard-config - configure: - - args: - - 'meson' - - '--native-file' - - '@SOURCE_ROOT@/userland/native-file.ini' - - '--cross-file' - - '@SOURCE_ROOT@/userland/cross-file.ini' - - '--prefix=/usr' - - '--libdir=lib' - - '--buildtype=release' - - '-Denable-docs=false' - - '-Denable-x11=true' - - '-Denable-wayland=false' - - '@THIS_SOURCE_DIR@' - build: - - args: ['ninja'] - - args: ['ninja', 'install'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - args: ['mkdir', '-p', "@THIS_COLLECT_DIR@/usr/share/X11/xkb"] - - - name: xkbutils - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/app/xkbutils.git' - tag: 'xkbutils-1.0.4' - version: '1.0.4' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['autoreconf', '-vfi'] - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-gcc - pkgs_required: - - mlibc - - xorg-util-macros - - xorg-proto - - libx11 - - libxt - - libxaw - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: xkeyboard-config - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config.git' - tag: 'xkeyboard-config-2.34' - version: '2.34' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - - host-gcc - pkgs_required: - - mlibc - - libx11 - - xorg-proto - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--with-xkb-rules-symlink=xorg' - - '--disable-nls' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: xf86-input-keyboard - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/driver/xf86-input-keyboard.git' - tag: 'xf86-input-keyboard-1.9.0' - version: '1.9.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-server - - xorg-util-macros - - libx11 - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' - - - name: xf86-video-fbdev - source: - subdir: 'bundled' - git: 'https://gitlab.freedesktop.org/xorg/driver/xf86-video-fbdev.git' - tag: 'xf86-video-fbdev-0.5.0' - version: '0.5.0' - tools_required: - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-libtool - - host-pkg-config - - host-xorg-macros - regenerate: - - args: ['./autogen.sh'] - environ: - NOCONFIGURE: 'yes' - tools_required: - - host-gcc - - host-autoconf-v2.69 - - host-automake-v1.16 - - host-pkg-config - pkgs_required: - - mlibc - - xorg-server - - xorg-util-macros - - libx11 - - libxrandr - - libxrender - - libxv - configure: - - args: - - '@THIS_SOURCE_DIR@/configure' - - '--host=x86_64-aero' - - '--prefix=/usr' - - '--sysconfdir=/etc' - - '--localstatedir=/var' - - '--disable-static' - - '--with-sysroot=@SYSROOT_DIR@' # Set libtool's lt_sysroot. - - '--disable-pciaccess' - environ: - SYSROOT: '@SYSROOT_DIR@' - build: - - args: ['make', '-j@PARALLELISM@'] - - args: ['make', 'install-strip'] - environ: - DESTDIR: '@THIS_COLLECT_DIR@' diff --git a/build-support/cross-llvm-config b/build-support/cross-llvm-config new file mode 100755 index 00000000000..0a8bf851e4f --- /dev/null +++ b/build-support/cross-llvm-config @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +# This file was taken from Managarm and I have no clue what it does. + +import argparse +import sys +import os + +our_version = 17 + + +def do_version(): + return '{}.0.6'.format(our_version) + + +def do_components(): + return 'all all-targets analysis asmparser asmprinter binaryformat bitreader bitwriter codegen core coroutines coverage debuginfocodeview debuginfodwarf debuginfomsf debuginfopdb demangle dlltooldriver engine executionengine fuzzmutate globalisel gtest gtest_main instcombine instrumentation interpreter ipo irreader libdriver lineeditor linker lto mc mcdisassembler mcjit mcparser mirparser native nativecodegen objcarcopts object objectyaml option orcjit passes profiledata runtimedyld scalaropts selectiondag support symbolize tablegen target testingsupport transformutils vectorize windowsmanifest x86 x86asmparser x86asmprinter x86codegen x86desc x86disassembler x86info x86utils' + + +def do_targets_built(): + return 'X86' + + +def get_includedir(): + return '/sysroot/usr/include' + + +def get_libdir(): + return '/sysroot/usr/lib' + + +def do_has_rtti(): + return 'YES' + + +def do_shared_mode(): + return 'shared' + + +def do_libs(): + return f'-lLLVM-{our_version}' + + +def do_system_libs(): + return f'-lLLVM-{our_version}' + + +def do_cppflags(): + return '' + + +def do_cxxflags(): + return '' + + +def do_ldflags(): + return '-L' + get_libdir() + + +parser = argparse.ArgumentParser() +parser.add_argument('--version', action='append_const', + dest='command', const=do_version) +parser.add_argument('--targets-built', action='append_const', + dest='command', const=do_targets_built) +parser.add_argument('--components', action='append_const', + dest='command', const=do_components) +parser.add_argument('--includedir', action='append_const', + dest='command', const=get_includedir) +parser.add_argument('--libdir', action='append_const', + dest='command', const=get_libdir) +parser.add_argument('--has-rtti', action='append_const', + dest='command', const=do_has_rtti) +parser.add_argument('--shared-mode', action='append_const', + dest='command', const=do_shared_mode) +parser.add_argument('--link-shared', action='store_const', + dest='link', const='shared') +parser.add_argument('--cppflags', action='append_const', + dest='command', const=do_cppflags) +parser.add_argument('--cxxflags', action='append_const', + dest='command', const=do_cxxflags) +parser.add_argument('--ldflags', action='append_const', + dest='command', const=do_ldflags) +parser.add_argument('--libs', action='append_const', + dest='command', const=do_libs) +parser.add_argument('--system-libs', action='append_const', + dest='command', const=do_system_libs) +parser.add_argument('components', type=str, nargs='*') + +print("cross-llvm-config:", sys.argv, file=sys.stderr) + +args = parser.parse_args() +for command in args.command: + result = command() + print("cross-llvm-config yields:", result, file=sys.stderr) + print(result) diff --git a/build-support/jwm/system.jwmrc b/build-support/jwm/system.jwmrc new file mode 100644 index 00000000000..031c5c4a3fa --- /dev/null +++ b/build-support/jwm/system.jwmrc @@ -0,0 +1,229 @@ + + + + + + + xterm + xfe + + audacious + xcalc + firefox + gimp + claws-mail + rox ~ + glxgears + gtk3-demo + + + xfontsel + + xprop | xmessage -file - + + + xwininfo | xmessage -file - + + + + + xscreensaver-command -lock + + + + + + + + + + + + xterm + + + + xclock + + + + + + + + root:1 + + showdesktop + + + + + + + + + + + + + + Sans-12:bold + 4 + 0 + #FFFFFF + #555555 + 0.5 + + #FFFFFF + #0077CC + 1.0 + + + + Sans-12 + #333333 + #FFFFFF + 0.75 + + + Sans-12 + + #FFFFFF + #555555 + + #FFFFFF + #333333 + + + #555555 + #333333 + #FFFFFF + + #0077CC + #004488 + + + + Sans-12 + #FFFFFF + #333333 + + #FFFFFF + #0077CC + + 0.85 + + + Sans-12 + #000000 + #999999 + + + + + /usr/local/share/icons/Tango/scalable/actions + + + /usr/local/share/icons/Tango/scalable/apps + + + /usr/local/share/icons/Tango/scalable/places + + + /usr/local/share/icons/Tango/scalable/status + + + /usr/local/share/icons/Tango/scalable/mimetypes + + + /usr/local/share/jwm + + + + + + + #111111 + + + + 400 + + + 2 + + + sloppy + + + border + + + opaque + + + opaque + + + up + down + right + left + left + down + up + right + select + escape + + nextstacked + close + desktop# + root:1 + window + maximize + rdesktop + ldesktop + udesktop + ddesktop + + + ldesktop + rdesktop + + move + move + window + shade + shade + maximize + + window + move + window + shade + shade + + resize + move + window + + close + move + close + + maximize + maxv + maxh + + minimize + move + shade + + diff --git a/build-support/limine.cfg b/build-support/limine.cfg new file mode 100644 index 00000000000..2ad5984fee2 --- /dev/null +++ b/build-support/limine.cfg @@ -0,0 +1,12 @@ +TIMEOUT=0 +VERBOSE=yes + +:aero +PROTOCOL=limine +KASLR=no +KERNEL_PATH=boot:///aero +CMDLINE=term-background=background theme-background=0x50000000 +#RESOLUTION=1920x1080 + +MODULE_PATH=boot:///term_background.bmp +MODULE_CMDLINE=background diff --git a/build-support/mkimage.sh b/build-support/mkimage.sh new file mode 100755 index 00000000000..eb6bb7b792d --- /dev/null +++ b/build-support/mkimage.sh @@ -0,0 +1,33 @@ +IMAGE_PATH=target/disk.img + +./target/jinx sysroot + +rm -rf $IMAGE_PATH + +dd if=/dev/zero of=$IMAGE_PATH bs=1G count=0 seek=512 +parted -s $IMAGE_PATH mklabel gpt +parted -s $IMAGE_PATH mkpart primary 2048s 100% + +# ensure loop kernel module is enabled +if ! lsmod | grep -q 'loop'; then + echo 'mkimage.sh: `loop` kernel module not found, attempting to load' + sudo modprobe loop +fi + +sudo losetup -Pf --show $IMAGE_PATH > loopback_dev +sudo mkfs.ext2 `cat loopback_dev`p1 -I128 + +rm -rf target/disk_image/ +mkdir target/disk_image +sudo mount `cat loopback_dev`p1 target/disk_image +sudo cp -r -v sysroot/. target/disk_image/ +pushd target/disk_image +sudo mkdir dev proc tmp +popd +sync +sudo umount target/disk_image/ +sudo losetup -d `cat loopback_dev` +sync + +rm -rf loopback_dev +rm -rf target/disk_image diff --git a/build-support/mkiso.sh b/build-support/mkiso.sh new file mode 100755 index 00000000000..4a0d021d9a9 --- /dev/null +++ b/build-support/mkiso.sh @@ -0,0 +1,24 @@ +set -ex + +./target/jinx host-build limine + +rm -rf target/iso_root +mkdir -pv target/iso_root/boot + +cp $1 target/iso_root/aero +cp build-support/limine.cfg src/.cargo/term_background.bmp target/iso_root/ + +# Install the limine binaries +cp host-pkgs/limine/usr/local/share/limine/limine-bios.sys target/iso_root/boot/ +cp host-pkgs/limine/usr/local/share/limine/limine-bios-cd.bin target/iso_root/boot/ +cp host-pkgs/limine/usr/local/share/limine/limine-uefi-cd.bin target/iso_root/boot/ +mkdir -pv target/iso_root/EFI/BOOT +cp host-pkgs/limine/usr/local/share/limine/BOOT*.EFI target/iso_root/EFI/BOOT/ + +# Create the disk image. +xorriso -as mkisofs -b boot/limine-bios-cd.bin -no-emul-boot -boot-load-size 4 \ + -boot-info-table --efi-boot boot/limine-uefi-cd.bin -efi-boot-part \ + --efi-boot-image --protective-msdos-label target/iso_root -o target/aero.iso + +# Install limine. +host-pkgs/limine/usr/local/bin/limine bios-install target/aero.iso diff --git a/extra-files/python/python-config-site b/build-support/python/python-config-site similarity index 100% rename from extra-files/python/python-config-site rename to build-support/python/python-config-site diff --git a/build-support/rust/config.toml b/build-support/rust/config.toml new file mode 100644 index 00000000000..32c4c163307 --- /dev/null +++ b/build-support/rust/config.toml @@ -0,0 +1,22 @@ +# [unstable] +# patch-in-config = true + +[build] +rustc = "/base_dir/host-pkgs/rust/bin/rustc" +target = "x86_64-unknown-aero" +rustflags = ["-C", "link-args=-no-pie", "-C", "link-args=-lgcc_s"] + +[target.x86_64-unknown-aero] +linker = "/base_dir/host-pkgs/gcc/usr/local/bin/x86_64-aero-gcc" + +[patch.crates-io] +libc = { path = "/base_dir/sources/rust-libc" } +# num_cpus = { path = "@SOURCE_ROOT@/bundled/rust-num-cpus" } +# users = { path = "@SOURCE_ROOT@/bundled/rust-users" } +# winit = { path = "@SOURCE_ROOT@/bundled/rust-winit" } +# nix = { path = "@SOURCE_ROOT@/bundled/rust-nix" } +# mio-06 = { path = "@SOURCE_ROOT@/bundled/rust-mio-0.6", package = "mio" } +# mio-08 = { path = "@SOURCE_ROOT@/bundled/rust-mio-0.8", package = "mio" } +# glutin = { path = "@SOURCE_ROOT@/bundled/rust-glutin/glutin" } +# shared_library = { path = "@SOURCE_ROOT@/bundled/rust-shared-library" } +# libloading = { path = "@SOURCE_ROOT@/bundled/rust-libloading" } diff --git a/build-support/rust/host-config.toml b/build-support/rust/host-config.toml new file mode 100644 index 00000000000..2ab356d1e3e --- /dev/null +++ b/build-support/rust/host-config.toml @@ -0,0 +1,2 @@ +[patch.crates-io] +libc = { path = "/base_dir/sources/rust-libc" } diff --git a/extra-files/firefox/mozconfig b/extra-files/firefox/mozconfig new file mode 100644 index 00000000000..fe6dcdbdeb6 --- /dev/null +++ b/extra-files/firefox/mozconfig @@ -0,0 +1,26 @@ +ac_add_options --disable-necko-wifi +ac_add_options --target=x86_64-aero +ac_add_options --with-toolchain-prefix=x86_64-aero +ac_add_options --enable-project=browser +ac_add_options --enable-alsa +ac_add_options --prefix=/usr + +ac_add_options --enable-optimize + +# use system libs if possible +ac_add_options --with-system-nss +ac_add_options --with-system-jpeg +ac_add_options --with-system-zlib +ac_add_options --with-system-icu +ac_add_options --with-system-libevent +ac_add_options --with-system-nspr +ac_add_options --with-system-nss +ac_add_options --with-system-webp + +ac_add_options --enable-default-toolkit=cairo-gtk3 + +ac_add_options --disable-pulseaudio +ac_add_options --disable-crashreporter +ac_add_options --disable-dbus +ac_add_options --disable-updater +ac_add_options --disable-tests diff --git a/extra-files/rust/config.toml b/extra-files/rust/config.toml deleted file mode 100644 index f278203c37c..00000000000 --- a/extra-files/rust/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[unstable] -patch-in-config = true - -[build] -rustc = "@BUILD_ROOT@/tools/host-rust/bin/rustc" -target = "x86_64-unknown-aero-system" -rustflags = ["-C", "link-args=-no-pie"] - -[target.x86_64-unknown-aero-system] -linker = "@BUILD_ROOT@/tools/host-gcc/bin/x86_64-aero-gcc" - -[patch.crates-io] -libc = { path = "@SOURCE_ROOT@/bundled/rust-libc" } -num_cpus = { path = "@SOURCE_ROOT@/bundled/rust-num-cpus" } -users = { path = "@SOURCE_ROOT@/bundled/rust-users" } diff --git a/extra-files/xorg/xinitrc b/extra-files/xorg/xinitrc new file mode 100644 index 00000000000..7a0c74fde5b --- /dev/null +++ b/extra-files/xorg/xinitrc @@ -0,0 +1,3 @@ +#!/bin/sh +dwm & +xwallpaper --zoom ~/wallpaper.png \ No newline at end of file diff --git a/host-recipes/autoconf b/host-recipes/autoconf new file mode 100644 index 00000000000..08a52ad8039 --- /dev/null +++ b/host-recipes/autoconf @@ -0,0 +1,16 @@ +name=autoconf +from_source=autoconf +revision=1 + +build() { + "${source_dir}"/configure --prefix="${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/autoconf-2.69 b/host-recipes/autoconf-2.69 new file mode 100644 index 00000000000..9593c60ac1d --- /dev/null +++ b/host-recipes/autoconf-2.69 @@ -0,0 +1,16 @@ +name=autoconf-2.69 +from_source=autoconf-2.69 +revision=1 + +build() { + "${source_dir}"/configure --prefix="${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/automake b/host-recipes/automake new file mode 100644 index 00000000000..ba10abce956 --- /dev/null +++ b/host-recipes/automake @@ -0,0 +1,21 @@ +name=automake +from_source=automake +revision=1 +hostdeps="autoconf" +imagedeps="gcc" + +build() { + "${source_dir}"/configure --prefix="${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + cp -pv /usr/local/share/autoconf/build-aux/config.sub "${dest_dir}${prefix}"/share/automake-1.16/ + cp -pv /usr/local/share/autoconf/build-aux/config.guess "${dest_dir}${prefix}"/share/automake-1.16/ + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/binutils b/host-recipes/binutils new file mode 100644 index 00000000000..1fa8fb86e0d --- /dev/null +++ b/host-recipes/binutils @@ -0,0 +1,24 @@ +name=binutils +from_source=binutils +revision=1 +imagedeps="gcc" +hostdeps="autoconf-2.69 automake libtool pkg-config" + +build() { + "${source_dir}"/configure \ + --prefix="${prefix}" \ + --target=${OS_TRIPLET} \ + --with-sysroot="${sysroot_dir}" \ + --disable-nls \ + --disable-werror \ + --disable-dependency-tracking + + make -j${parallelism} all +} + +package() { + DESTDIR="${dest_dir}" make install + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/cmake b/host-recipes/cmake new file mode 100644 index 00000000000..31536bc001b --- /dev/null +++ b/host-recipes/cmake @@ -0,0 +1,18 @@ +name=cmake +from_source=cmake +revision=1 +imagedeps="gcc" + +build() { + "${source_dir}"/configure --prefix="${prefix}" --parallel="${parallelism}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + echo 'include(Platform/UnixPaths)' > "${dest_dir}${prefix}/share/cmake-3.27/Modules/Platform/Aero.cmake" + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/gcc b/host-recipes/gcc new file mode 100644 index 00000000000..a102d4ab4e4 --- /dev/null +++ b/host-recipes/gcc @@ -0,0 +1,38 @@ +name=gcc +from_source=gcc-host +revision=1 +imagedeps="gcc" +hostdeps="autoconf-2.69 automake libtool pkg-config" +hostrundeps="binutils" +deps="mlibc-headers" + +build() { + cp -rp "${source_dir}"/. ./ + + mkdir build && cd build + + CXXFLAGS_FOR_TARGET="$CFLAGS" \ + CFLAGS_FOR_TARGET="$CFLAGS" \ + ../configure \ + --prefix="${prefix}" \ + --target=${OS_TRIPLET} \ + --with-sysroot="${sysroot_dir}" \ + --disable-nls \ + --enable-languages=c,c++,lto \ + --disable-multilib \ + --enable-initfini-array \ + --enable-shared \ + --enable-host-shared + + make -j${parallelism} all-gcc +} + +package() { + cd build + DESTDIR="${dest_dir}" make install-gcc + + ln -s ${OS_TRIPLET}-gcc "${dest_dir}${prefix}/bin/${OS_TRIPLET}-cc" + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/gnulib b/host-recipes/gnulib new file mode 100644 index 00000000000..a0711c37a7b --- /dev/null +++ b/host-recipes/gnulib @@ -0,0 +1,3 @@ +name=gnulib +from_source=gnulib +revision=1 diff --git a/host-recipes/intltool b/host-recipes/intltool new file mode 100644 index 00000000000..3825495b4d0 --- /dev/null +++ b/host-recipes/intltool @@ -0,0 +1,20 @@ +name=intltool +from_source=intltool +revision=1 +hostdeps="autoconf automake libtool pkg-config" +imagedeps="gcc perl-xml-parser" + +build() { + #cp -rp "${source_dir}"/. ./ + ${source_dir}/configure \ + --prefix="${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/libgcc-binaries b/host-recipes/libgcc-binaries new file mode 100644 index 00000000000..6328e669e67 --- /dev/null +++ b/host-recipes/libgcc-binaries @@ -0,0 +1,8 @@ +name=libgcc-binaries +from_source=libgcc-binaries +revision=1 + +package() { + mkdir -p ${dest_dir}${prefix}/libgcc-binaries + cp -rv ${source_dir}/. ${dest_dir}${prefix}/libgcc-binaries/ +} diff --git a/host-recipes/libtool b/host-recipes/libtool new file mode 100644 index 00000000000..3141fc5d9e3 --- /dev/null +++ b/host-recipes/libtool @@ -0,0 +1,23 @@ +name=libtool +from_source=libtool +revision=1 +hostdeps="autoconf automake" +imagedeps="help2man gcc" + +build() { + cp -rp "${source_dir}"/. ./ + ./configure \ + --prefix="${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + cp -pv /usr/local/share/autoconf/build-aux/config.sub "${dest_dir}${prefix}"/share/libtool/build-aux/ + cp -pv /usr/local/share/autoconf/build-aux/config.guess "${dest_dir}${prefix}"/share/libtool/build-aux/ + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/limine b/host-recipes/limine new file mode 100644 index 00000000000..d93f3e397db --- /dev/null +++ b/host-recipes/limine @@ -0,0 +1,24 @@ +name=limine +from_source=limine +revision=1 +hostdeps="gcc pkg-config" +imagedeps="nasm gcc mtools" + +build() { + "${source_dir}"/configure \ + --enable-uefi-ia32 \ + --enable-uefi-x86-64 \ + --enable-uefi-cd \ + --enable-bios \ + --enable-bios-cd \ + --enable-bios-pxe + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/llvm b/host-recipes/llvm new file mode 100644 index 00000000000..6bfe5294b3b --- /dev/null +++ b/host-recipes/llvm @@ -0,0 +1,27 @@ +name=llvm +version=17.0.6 +revision=1 +from_source=llvm-host +imagedeps="gcc cmake ninja git" +source_deps="binutils" + +build() { + cmake \ + -GNinja \ + -DCMAKE_INSTALL_PREFIX="${prefix}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_TARGETS_TO_BUILD=X86 \ + -DLLVM_ENABLE_PROJECTS="llvm;clang;clang-tools-extra" \ + -DDEFAULT_SYSROOT="${sysroot_dir}" \ + -DLLVM_BINUTILS_INCDIR="${source_dir}/../binutils/include" \ + "${source_dir}/llvm" + + ninja -j ${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/pkg-config b/host-recipes/pkg-config new file mode 100644 index 00000000000..ee2b4f6a190 --- /dev/null +++ b/host-recipes/pkg-config @@ -0,0 +1,28 @@ +name=pkg-config +from_source=pkg-config +revision=1 +imagedeps="gcc" +hostdeps="automake autoconf libtool" + +build() { + "${source_dir}"/configure \ + --prefix="${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + mkdir -p "${dest_dir}${prefix}/share/pkgconfig/personality.d" + cat <"${dest_dir}${prefix}/share/pkgconfig/personality.d/${OS_TRIPLET}.personality" +Triplet: ${OS_TRIPLET} +SysrootDir: ${sysroot_dir} +DefaultSearchPaths: ${sysroot_dir}/usr/lib/pkgconfig:${sysroot_dir}/usr/share/pkgconfig +SystemIncludePaths: ${sysroot_dir}/usr/include +SystemLibraryPaths: ${sysroot_dir}/usr/lib +EOF + ln -s pkgconf "${dest_dir}${prefix}/bin/${OS_TRIPLET}-pkg-config" + + strip_command=strip \ + post_package_strip +} diff --git a/host-recipes/rust b/host-recipes/rust new file mode 100644 index 00000000000..f81ef8402f5 --- /dev/null +++ b/host-recipes/rust @@ -0,0 +1,25 @@ +name=rust +revision=1 +from_source=rust-host +hostdeps="llvm gcc rust-libc" +source_deps="rust-libc" +imagedeps="python git wget gcc" +allow_network="yes" + +build() { + echo "Patching out rust memes..." + cp -rp "${source_dir}/." ./ + + mkdir /tmp/cargo + cp ${base_dir}/build-support/rust/host-config.toml /tmp/cargo/config.toml + CARGO_HOME=/tmp/cargo ./x.py build --stage 2 -j${parallelism} --verbose +} + +package() { + CARGO_HOME=/tmp/cargo DESTDIR="${dest_dir}" ./x.py install -j${parallelism} + + find ${dest_dir} -name "*.old" -delete + + strip_command=strip + post_package_strip +} diff --git a/host-recipes/rust-libc b/host-recipes/rust-libc new file mode 100644 index 00000000000..1b29226398a --- /dev/null +++ b/host-recipes/rust-libc @@ -0,0 +1,3 @@ +name=rust-libc +from_source=rust-libc +revision=1 diff --git a/improving-build-times.txt b/improving-build-times.txt new file mode 100644 index 00000000000..6b611793f40 --- /dev/null +++ b/improving-build-times.txt @@ -0,0 +1,7 @@ +total_build: 28.36s +rebuild: 8.27s + +16/3/2024 +--------- +total_build: 27.29s +rebuild: 9.50s diff --git a/jinx-config b/jinx-config new file mode 100644 index 00000000000..fe0d9974467 --- /dev/null +++ b/jinx-config @@ -0,0 +1,72 @@ +JINX_MAJOR_VER=0.2 + +export CFLAGS='-O2 -pipe' +export CXXFLAGS="${CFLAGS}" + +OS_TRIPLET=x86_64-aero +export CARGO_HOME="${base_dir}/target/cargo-home" + +# Required by scripts/mkimage +imagedeps="parted" + +autotools_recursive_regen() { + ACLOCAL_INCLUDE="" + if [ -d ${sysroot_dir}/usr/share/aclocal ]; then + ACLOCAL_INCLUDE="-I${sysroot_dir}/usr/share/aclocal" + fi + + for f in $(find . -name configure.ac -type f); do + echo "* autotools regen in '$(dirname $f)'..." + ( cd "$(dirname "$f")" && autoreconf -fvi "$@" $ACLOCAL_INCLUDE ) + done +} + +post_package_strip() { + if [ -z "$strip_command" ]; then + strip_command="${OS_TRIPLET}-strip" + fi + + for f in $(find "${dest_dir}"); do + if file "$f" | grep 'not stripped' >/dev/null; then + echo "* stripping '$f'..." + stripped_file="$(mktemp)" + ${strip_command} "$f" -o "$stripped_file" + chmod --reference="$f" "$stripped_file" + mv -f "$stripped_file" "$f" + fi + done +} + +autotools_configure() { + if [ -z "${configure_script_path}" ]; then + configure_script_path="${source_dir}/configure" + fi + + ${configure_script_path} \ + --host=${OS_TRIPLET} \ + --with-sysroot=${sysroot_dir} \ + --prefix=${prefix} \ + --sysconfdir=/etc \ + --localstatedir=/var \ + --libdir=${prefix}/lib \ + --disable-static \ + --enable-shared \ + --disable-malloc0returnsnull \ + "$@" +} + +meson_configure() { + if [ -z "${meson_source_dir}" ]; then + meson_source_dir="${source_dir}" + fi + + # TODO(andypython): Move cross-file.ini to build-support/ + meson setup "${meson_source_dir}" \ + --cross-file "${base_dir}/userland/cross-file.ini" \ + --prefix=${prefix} \ + --sysconfdir=/etc \ + --libdir=lib \ + --buildtype=release \ + -Ddefault_library=shared \ + "$@" +} diff --git a/misc/aero-doom.png b/misc/aero-doom.png deleted file mode 100644 index 08e58360482..00000000000 Binary files a/misc/aero-doom.png and /dev/null differ diff --git a/misc/demo.png b/misc/demo.png deleted file mode 100644 index bef3184bb84..00000000000 Binary files a/misc/demo.png and /dev/null differ diff --git a/misc/dwm-alacritty-glxgears.png b/misc/dwm-alacritty-glxgears.png new file mode 100644 index 00000000000..e700524fa25 Binary files /dev/null and b/misc/dwm-alacritty-glxgears.png differ diff --git a/misc/gpl.png b/misc/gpl.png new file mode 100644 index 00000000000..24727f3e28f Binary files /dev/null and b/misc/gpl.png differ diff --git a/misc/qjs-in-aero.png b/misc/qjs-in-aero.png deleted file mode 100644 index 21bbe0bd264..00000000000 Binary files a/misc/qjs-in-aero.png and /dev/null differ diff --git a/patched.txt b/patched.txt new file mode 100644 index 00000000000..f1b4bdf79af --- /dev/null +++ b/patched.txt @@ -0,0 +1,5 @@ +bootstrap-host-gcc +llvm +rust-libc +webkitgtk +pixman diff --git a/patches/autoconf/jinx-working-patch.patch b/patches/autoconf/jinx-working-patch.patch new file mode 100644 index 00000000000..b4e4be02eec --- /dev/null +++ b/patches/autoconf/jinx-working-patch.patch @@ -0,0 +1,47 @@ +diff --git autoconf-clean/build-aux/config.guess autoconf-workdir/build-aux/config.guess +index cdfc439..0e1b56a 100755 +--- autoconf-clean/build-aux/config.guess ++++ autoconf-workdir/build-aux/config.guess +@@ -4,7 +4,8 @@ + + # shellcheck disable=SC2006,SC2268 # see below for rationale + +-timestamp='2023-08-22' ++# timestamp it to always be newer ++timestamp='9999-99-99' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -933,6 +934,9 @@ EOF + i*:PW*:*) + GUESS=$UNAME_MACHINE-pc-pw32 + ;; ++ *:Aero:*:*) ++ GUESS=$UNAME_MACHINE-pc-aero ++ ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; +diff --git autoconf-clean/build-aux/config.sub autoconf-workdir/build-aux/config.sub +index defe52c..8600125 100755 +--- autoconf-clean/build-aux/config.sub ++++ autoconf-workdir/build-aux/config.sub +@@ -4,7 +4,8 @@ + + # shellcheck disable=SC2006,SC2268 # see below for rationale + +-timestamp='2023-09-19' ++# timestamp it to always be newer ++timestamp='9999-99-99' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -1749,7 +1750,7 @@ case $os in + | mirbsd* | netbsd* | dicos* | openedition* | ose* \ + | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ + | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ +- | bosx* | nextstep* | cxux* | oabi* \ ++ | bosx* | nextstep* | cxux* | oabi* | aero* \ + | ptx* | ecoff* | winnt* | domain* | vsta* \ + | udi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* | serenity* \ diff --git a/patches/automake-v1.16/automake-v1.16.patch b/patches/automake-v1.16/automake-v1.16.patch deleted file mode 100644 index d0760f5c71a..00000000000 --- a/patches/automake-v1.16/automake-v1.16.patch +++ /dev/null @@ -1,26 +0,0 @@ -From bd762227b35e7afac102348e88f1aee3cfcab9c9 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Thu, 30 Dec 2021 13:16:15 +1100 -Subject: [PATCH] config.sub: add aero target - -Signed-off-by: Andy-Python-Programmer ---- - lib/config.sub | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/config.sub b/lib/config.sub -index d74fb6d..194fc2c 100755 ---- a/lib/config.sub -+++ b/lib/config.sub -@@ -1723,7 +1723,7 @@ case $os in - | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ - | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ - | hiux* | abug | nacl* | netware* | windows* \ -- | os9* | macos* | osx* | ios* \ -+ | os9* | macos* | osx* | ios* | aero* \ - | mpw* | magic* | mmixware* | mon960* | lnews* \ - | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ - | aos* | aros* | cloudabi* | sortix* | twizzler* \ --- -2.25.1 - diff --git a/patches/bash/bash.patch b/patches/bash/bash.patch deleted file mode 100644 index ea6a0e0b730..00000000000 --- a/patches/bash/bash.patch +++ /dev/null @@ -1,282 +0,0 @@ -From 50a9f0c440ae12cb24316ae5397976ab83ea7e6a Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Tue, 18 Jan 2022 13:35:43 +1100 -Subject: [PATCH] bash: add aero port - -Signed-off-by: Andy-Python-Programmer ---- - .vscode/settings.json | 3 +++ - builtins/psize.c | 19 +++------------- - lib/readline/terminal.c | 2 +- - lib/termcap/termcap.c | 2 +- - mksyntax.c | 48 ++--------------------------------------- - shell.c | 4 ++-- - support/bashversion.c | 7 ++---- - support/config.sub | 2 +- - support/man2html.c | 5 +++-- - support/mksignames.c | 2 -- - support/signames.c | 2 -- - 11 files changed, 18 insertions(+), 78 deletions(-) - create mode 100644 .vscode/settings.json - -diff --git a/.vscode/settings.json b/.vscode/settings.json -new file mode 100644 -index 0000000..9792498 ---- /dev/null -+++ b/.vscode/settings.json -@@ -0,0 +1,3 @@ -+{ -+ "editor.formatOnSave": false -+} -\ No newline at end of file -diff --git a/builtins/psize.c b/builtins/psize.c -index 30881fb..be9c84b 100644 ---- a/builtins/psize.c -+++ b/builtins/psize.c -@@ -21,25 +21,12 @@ - /* Write output in 128-byte chunks until we get a sigpipe or write gets an - EPIPE. Then report how many bytes we wrote. We assume that this is the - pipe size. */ --#include -- --#if defined (HAVE_UNISTD_H) --# ifdef _MINIX --# include --# endif --# include --#endif - - #include --#ifndef _MINIX --#include "../bashtypes.h" --#endif -+#include - #include - #include -- --#include "../command.h" --#include "../general.h" --#include "../sig.h" -+#include - - #ifndef errno - extern int errno; -@@ -47,7 +34,7 @@ extern int errno; - - int nw; - --sighandler -+void - sigpipe (sig) - int sig; - { -diff --git a/lib/readline/terminal.c b/lib/readline/terminal.c -index 05415dc..a6b5307 100644 ---- a/lib/readline/terminal.c -+++ b/lib/readline/terminal.c -@@ -103,7 +103,7 @@ static char *term_string_buffer = (char *)NULL; - static int tcap_initialized; - - #if !defined (__linux__) && !defined (NCURSES_VERSION) --# if defined (__EMX__) || defined (NEED_EXTERN_PC) -+# if defined (__EMX__) || defined (__aero__) || defined (NEED_EXTERN_PC) - extern - # endif /* __EMX__ || NEED_EXTERN_PC */ - char PC, *BC, *UP; -diff --git a/lib/termcap/termcap.c b/lib/termcap/termcap.c -index ba3dab2..2882f0c 100644 ---- a/lib/termcap/termcap.c -+++ b/lib/termcap/termcap.c -@@ -627,7 +627,7 @@ scan_file (str, fd, bufp) - bufp->ateof = 0; - *bufp->ptr = '\0'; - -- lseek (fd, 0L, 0); -+ lseek (fd, 0L, SEEK_SET); - - while (!bufp->ateof) - { -diff --git a/mksyntax.c b/mksyntax.c -index 0385686..1a73eca 100644 ---- a/mksyntax.c -+++ b/mksyntax.c -@@ -20,16 +20,12 @@ - along with Bash. If not, see . - */ - --#include "config.h" -- - #include -+#include - #include "bashansi.h" - #include "chartypes.h" - #include -- --#ifdef HAVE_UNISTD_H --# include --#endif -+#include - - #include "syntax.h" - -@@ -40,9 +36,7 @@ extern char *optarg; - extern int errno; - #endif - --#ifndef HAVE_STRERROR - extern char *strerror(); --#endif - - struct wordflag { - int flag; -@@ -375,41 +369,3 @@ main(argc, argv) - fclose (fp); - exit (0); - } -- -- --#if !defined (HAVE_STRERROR) -- --#include --#if defined (HAVE_SYS_PARAM_H) --# include --#endif -- --#if defined (HAVE_UNISTD_H) --# include --#endif -- --/* Return a string corresponding to the error number E. From -- the ANSI C spec. */ --#if defined (strerror) --# undef strerror --#endif -- --char * --strerror (e) -- int e; --{ -- static char emsg[40]; --#if defined (HAVE_SYS_ERRLIST) -- extern int sys_nerr; -- extern char *sys_errlist[]; -- -- if (e > 0 && e < sys_nerr) -- return (sys_errlist[e]); -- else --#endif /* HAVE_SYS_ERRLIST */ -- { -- sprintf (emsg, "Unknown system error %d", e); -- return (&emsg[0]); -- } --} --#endif /* HAVE_STRERROR */ -diff --git a/shell.c b/shell.c -index ce8087f..b7475dd 100644 ---- a/shell.c -+++ b/shell.c -@@ -1614,7 +1614,7 @@ open_shell_script (script_name) - #endif - - /* Only do this with non-tty file descriptors we can seek on. */ -- if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) -+ if (fd_is_tty == 0 && (lseek (fd, 0L, SEEK_CUR) != -1)) - { - /* Check to see if the `file' in `bash file' is a binary file - according to the same tests done by execute_simple_command (), -@@ -1651,7 +1651,7 @@ open_shell_script (script_name) - exit (EX_BINARY_FILE); - } - /* Now rewind the file back to the beginning. */ -- lseek (fd, 0L, 0); -+ lseek (fd, 0L, SEEK_SET); - } - - /* Open the script. But try to move the file descriptor to a randomly -diff --git a/support/bashversion.c b/support/bashversion.c -index 4f86b13..64779de 100644 ---- a/support/bashversion.c -+++ b/support/bashversion.c -@@ -18,15 +18,12 @@ - along with Bash. If not, see . - */ - --#include "config.h" -- - #include "stdc.h" - - #include -+#include - --#if defined (HAVE_UNISTD_H) --# include --#endif -+#include - - #include "bashansi.h" - -diff --git a/support/config.sub b/support/config.sub -index c874b7a..4ce3963 100755 ---- a/support/config.sub -+++ b/support/config.sub -@@ -1707,7 +1707,7 @@ case $os in - | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ - | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ - | udi* | lites* | ieee* | go32* | aux* | hcos* \ -- | chorusrdb* | cegcc* | glidix* \ -+ | chorusrdb* | cegcc* | glidix* | aero* \ - | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ - | midipix* | mingw32* | mingw64* | mint* \ - | uxpv* | beos* | mpeix* | udk* | moxiebox* \ -diff --git a/support/man2html.c b/support/man2html.c -index e6f441b..f02453d 100644 ---- a/support/man2html.c -+++ b/support/man2html.c -@@ -63,7 +63,7 @@ - * time to look through all the available manpages.) - */ - #ifdef HAVE_CONFIG_H --#include -+//#include - #endif - - #define NROFF 0 -@@ -123,7 +123,8 @@ char *manpage; - #define BD_LITERAL 1 - #define BD_INDENT 2 - --#ifndef HAVE_STRERROR -+//#ifndef HAVE_STRERROR -+#if (0) - static char * - strerror(int e) - { -diff --git a/support/mksignames.c b/support/mksignames.c -index ba87ae8..4b39787 100644 ---- a/support/mksignames.c -+++ b/support/mksignames.c -@@ -19,8 +19,6 @@ - along with Bash. If not, see . - */ - --#include -- - #include - #include - -diff --git a/support/signames.c b/support/signames.c -index aba4842..b4bbdc6 100644 ---- a/support/signames.c -+++ b/support/signames.c -@@ -18,8 +18,6 @@ - along with Bash. If not, see . - */ - --#include -- - #include - - #include --- -2.25.1 - diff --git a/patches/bash/jinx-working-patch.patch b/patches/bash/jinx-working-patch.patch new file mode 100644 index 00000000000..ff0943d4732 --- /dev/null +++ b/patches/bash/jinx-working-patch.patch @@ -0,0 +1,368 @@ +diff --git bash-clean/builtins/psize.c bash-workdir/builtins/psize.c +index 30881fb..6c99972 100644 +--- bash-clean/builtins/psize.c ++++ bash-workdir/builtins/psize.c +@@ -21,33 +21,36 @@ + /* Write output in 128-byte chunks until we get a sigpipe or write gets an + EPIPE. Then report how many bytes we wrote. We assume that this is the + pipe size. */ +-#include +- +-#if defined (HAVE_UNISTD_H) +-# ifdef _MINIX +-# include +-# endif +-# include +-#endif +- +-#include +-#ifndef _MINIX +-#include "../bashtypes.h" +-#endif ++// #include ++ ++// #if defined (HAVE_UNISTD_H) ++// # ifdef _MINIX ++// # include ++// # endif ++// # include ++// #endif ++ ++// #include ++// #ifndef _MINIX ++// #include "../bashtypes.h" ++// #endif + #include +-#include ++// #include + +-#include "../command.h" +-#include "../general.h" +-#include "../sig.h" ++// #include "../command.h" ++// #include "../general.h" ++// #include "../sig.h" + +-#ifndef errno +-extern int errno; +-#endif ++// #ifndef errno ++// extern int errno; ++// #endif ++#include ++#include ++#include + + int nw; + +-sighandler ++void + sigpipe (sig) + int sig; + { +diff --git bash-clean/lib/termcap/termcap.c bash-workdir/lib/termcap/termcap.c +index 87fae05..ed9d105 100644 +--- bash-clean/lib/termcap/termcap.c ++++ bash-workdir/lib/termcap/termcap.c +@@ -630,7 +630,7 @@ scan_file (str, fd, bufp) + bufp->ateof = 0; + *bufp->ptr = '\0'; + +- lseek (fd, 0L, 0); ++ lseek (fd, 0L, SEEK_SET); + + while (!bufp->ateof) + { +diff --git bash-clean/mksyntax.c bash-workdir/mksyntax.c +index 0385686..53011a2 100644 +--- bash-clean/mksyntax.c ++++ bash-workdir/mksyntax.c +@@ -20,29 +20,31 @@ + along with Bash. If not, see . + */ + +-#include "config.h" ++// #include "config.h" + ++#include + #include + #include "bashansi.h" + #include "chartypes.h" + #include + +-#ifdef HAVE_UNISTD_H +-# include +-#endif ++// #ifdef HAVE_UNISTD_H ++// # include ++// #endif ++#include + + #include "syntax.h" + + extern int optind; + extern char *optarg; + +-#ifndef errno +-extern int errno; +-#endif ++// #ifndef errno ++// extern int errno; ++// #endif + +-#ifndef HAVE_STRERROR +-extern char *strerror(); +-#endif ++// #ifndef HAVE_STRERROR ++// extern char *strerror(); ++// #endif + + struct wordflag { + int flag; +@@ -377,39 +379,39 @@ main(argc, argv) + } + + +-#if !defined (HAVE_STRERROR) +- +-#include +-#if defined (HAVE_SYS_PARAM_H) +-# include +-#endif +- +-#if defined (HAVE_UNISTD_H) +-# include +-#endif +- +-/* Return a string corresponding to the error number E. From +- the ANSI C spec. */ +-#if defined (strerror) +-# undef strerror +-#endif +- +-char * +-strerror (e) +- int e; +-{ +- static char emsg[40]; +-#if defined (HAVE_SYS_ERRLIST) +- extern int sys_nerr; +- extern char *sys_errlist[]; +- +- if (e > 0 && e < sys_nerr) +- return (sys_errlist[e]); +- else +-#endif /* HAVE_SYS_ERRLIST */ +- { +- sprintf (emsg, "Unknown system error %d", e); +- return (&emsg[0]); +- } +-} +-#endif /* HAVE_STRERROR */ ++// #if !defined (HAVE_STRERROR) ++ ++// #include ++// #if defined (HAVE_SYS_PARAM_H) ++// # include ++// #endif ++ ++// #if defined (HAVE_UNISTD_H) ++// # include ++// #endif ++ ++// /* Return a string corresponding to the error number E. From ++// the ANSI C spec. */ ++// #if defined (strerror) ++// # undef strerror ++// #endif ++ ++// char * ++// strerror (e) ++// int e; ++// { ++// static char emsg[40]; ++// #if defined (HAVE_SYS_ERRLIST) ++// extern int sys_nerr; ++// extern char *sys_errlist[]; ++ ++// if (e > 0 && e < sys_nerr) ++// return (sys_errlist[e]); ++// else ++// #endif /* HAVE_SYS_ERRLIST */ ++// { ++// sprintf (emsg, "Unknown system error %d", e); ++// return (&emsg[0]); ++// } ++// } ++// #endif /* HAVE_STRERROR */ +diff --git bash-clean/shell.c bash-workdir/shell.c +index ebd8965..05d6a85 100644 +--- bash-clean/shell.c ++++ bash-workdir/shell.c +@@ -1647,7 +1647,7 @@ open_shell_script (script_name) + #endif + + /* Only do this with non-tty file descriptors we can seek on. */ +- if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) ++ if (fd_is_tty == 0 && (lseek (fd, 0L, SEEK_CUR) != -1)) + { + /* Check to see if the `file' in `bash file' is a binary file + according to the same tests done by execute_simple_command (), +@@ -1684,7 +1684,7 @@ open_shell_script (script_name) + exit (EX_BINARY_FILE); + } + /* Now rewind the file back to the beginning. */ +- lseek (fd, 0L, 0); ++ lseek (fd, 0L, SEEK_SET); + } + + /* Open the script. But try to move the file descriptor to a randomly +diff --git bash-clean/support/bashversion.c bash-workdir/support/bashversion.c +index ad02d46..1b8a4ae 100644 +--- bash-clean/support/bashversion.c ++++ bash-workdir/support/bashversion.c +@@ -18,15 +18,17 @@ + along with Bash. If not, see . + */ + +-#include "config.h" ++// #include "config.h" + + #include "stdc.h" + + #include ++#include + +-#if defined (HAVE_UNISTD_H) +-# include +-#endif ++// #if defined (HAVE_UNISTD_H) ++// # include ++// #endif ++#include + + #include "bashansi.h" + +diff --git bash-clean/support/man2html.c bash-workdir/support/man2html.c +index e6f441b..906e9f8 100644 +--- bash-clean/support/man2html.c ++++ bash-workdir/support/man2html.c +@@ -62,9 +62,9 @@ + * that all these features work on all manpages. (I didn't have the + * time to look through all the available manpages.) + */ +-#ifdef HAVE_CONFIG_H +-#include +-#endif ++// #ifdef HAVE_CONFIG_H ++// #include ++// #endif + + #define NROFF 0 + +@@ -123,26 +123,26 @@ char *manpage; + #define BD_LITERAL 1 + #define BD_INDENT 2 + +-#ifndef HAVE_STRERROR +-static char * +-strerror(int e) +-{ +- static char emsg[40]; +- +-#if defined (HAVE_SYS_ERRLIST) +- extern int sys_nerr; +- extern char *sys_errlist[]; +- +- if (e > 0 && e < sys_nerr) +- return (sys_errlist[e]); +- else +-#endif /* HAVE_SYS_ERRLIST */ +- { +- sprintf(emsg, "Unknown system error %d", e); +- return (&emsg[0]); +- } +-} +-#endif /* !HAVE_STRERROR */ ++// #ifndef HAVE_STRERROR ++// static char * ++// strerror(int e) ++// { ++// static char emsg[40]; ++ ++// #if defined (HAVE_SYS_ERRLIST) ++// extern int sys_nerr; ++// extern char *sys_errlist[]; ++ ++// if (e > 0 && e < sys_nerr) ++// return (sys_errlist[e]); ++// else ++// #endif /* HAVE_SYS_ERRLIST */ ++// { ++// sprintf(emsg, "Unknown system error %d", e); ++// return (&emsg[0]); ++// } ++// } ++// #endif /* !HAVE_STRERROR */ + + static char * + strgrow(char *old, int len) +diff --git bash-clean/support/mksignames.c bash-workdir/support/mksignames.c +index ba87ae8..bd13bab 100644 +--- bash-clean/support/mksignames.c ++++ bash-workdir/support/mksignames.c +@@ -19,17 +19,18 @@ + along with Bash. If not, see . + */ + +-#include ++// #include + + #include + #include + + #include +-#if defined (HAVE_STDLIB_H) +-# include +-#else +-# include "ansi_stdlib.h" +-#endif /* HAVE_STDLIB_H */ ++// #if defined (HAVE_STDLIB_H) ++// # include ++// #else ++// # include "ansi_stdlib.h" ++// #endif /* HAVE_STDLIB_H */ ++#include + + /* Duplicated from signames.c */ + #if !defined (NSIG) +diff --git bash-clean/support/signames.c bash-workdir/support/signames.c +index 84864fd..6b4e29f 100644 +--- bash-clean/support/signames.c ++++ bash-workdir/support/signames.c +@@ -18,18 +18,19 @@ + along with Bash. If not, see . + */ + +-#include ++// #include + + #include + + #include + #include + +-#if defined (HAVE_STDLIB_H) +-# include +-#else +-# include "ansi_stdlib.h" +-#endif /* HAVE_STDLIB_H */ ++// #if defined (HAVE_STDLIB_H) ++// # include ++// #else ++// # include "ansi_stdlib.h" ++// #endif /* HAVE_STDLIB_H */ ++#include + + #if !defined (NSIG) + # define NSIG 64 diff --git a/patches/binutils/binutils.patch b/patches/binutils/binutils.patch deleted file mode 100644 index 3e2580aa27f..00000000000 --- a/patches/binutils/binutils.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 23c517e8985baa0b4a788186d53e6299f72d48d0 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Tue, 31 Aug 2021 11:15:02 +1000 -Subject: [PATCH] targets: add aero target port - -Signed-off-by: Andy-Python-Programmer ---- - .vscode/settings.json | 6 ++++++ - bfd/config.bfd | 5 +++++ - config.sub | 2 +- - gas/configure.tgt | 1 + - ld/configure.tgt | 4 ++++ - 5 files changed, 17 insertions(+), 1 deletion(-) - create mode 100644 .vscode/settings.json - -diff --git a/.vscode/settings.json b/.vscode/settings.json -new file mode 100644 -index 00000000..7a72e53f ---- /dev/null -+++ b/.vscode/settings.json -@@ -0,0 +1,6 @@ -+{ -+ "editor.formatOnSave": false, -+ "files.associations": { -+ "inttypes.h": "c" -+ } -+} -\ No newline at end of file -diff --git a/bfd/config.bfd b/bfd/config.bfd -index 30087e3b..5f204466 100644 ---- a/bfd/config.bfd -+++ b/bfd/config.bfd -@@ -719,6 +719,11 @@ case "${targ}" in - targ_defvec=i386_elf32_vec - targ_selvecs="iamcu_elf32_vec i386_pe_vec i386_pei_vec" - ;; -+ x86_64-*-aero*) -+ targ_defvec=x86_64_elf64_vec -+ targ_selvecs=i386_elf32_vec -+ want64=true -+ ;; - i[3-7]86-*-interix*) - targ_defvec=i386_pei_vec - targ_selvecs="i386_pe_vec" -diff --git a/config.sub b/config.sub -index 7384e919..e1e5c644 100755 ---- a/config.sub -+++ b/config.sub -@@ -1704,7 +1704,7 @@ case $os in - | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ - | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ - | hiux* | abug | nacl* | netware* | windows* \ -- | os9* | macos* | osx* | ios* \ -+ | os9* | macos* | osx* | ios* | aero* \ - | mpw* | magic* | mmixware* | mon960* | lnews* \ - | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ - | aos* | aros* | cloudabi* | sortix* | twizzler* \ -diff --git a/gas/configure.tgt b/gas/configure.tgt -index 338892ad..d1a9ac68 100644 ---- a/gas/configure.tgt -+++ b/gas/configure.tgt -@@ -221,6 +221,7 @@ case ${generic_target} in - i386-*-beos*) fmt=elf ;; - i386-*-elfiamcu) fmt=elf arch=iamcu ;; - i386-*-elf*) fmt=elf ;; -+ i386-*-aero*) fmt=elf ;; - i386-*-fuchsia*) fmt=elf ;; - i386-*-genode*) fmt=elf ;; - i386-*-bsd*) fmt=aout em=386bsd ;; -diff --git a/ld/configure.tgt b/ld/configure.tgt -index 6205d7c9..5cd3f070 100644 ---- a/ld/configure.tgt -+++ b/ld/configure.tgt -@@ -323,6 +323,10 @@ i[3-7]86-*-linux-*) targ_emul=elf_i386 - targ64_extra_emuls="elf_x86_64 elf32_x86_64 elf_l1om elf_k1om" - targ64_extra_libpath="elf_x86_64 elf32_x86_64" - ;; -+x86_64-*-aero*) -+ targ_emul=elf_x86_64 -+ targ_extra_emuls=elf_i386 -+ ;; - i[3-7]86-*-redox*) targ_emul=elf_i386 - targ_extra_emuls=elf_x86_64 - ;; --- -2.25.1 - diff --git a/patches/binutils/jinx-working-patch.patch b/patches/binutils/jinx-working-patch.patch new file mode 100644 index 00000000000..2e63a00fa3d --- /dev/null +++ b/patches/binutils/jinx-working-patch.patch @@ -0,0 +1,154 @@ +diff --git binutils-clean/bfd/Makefile.am binutils-workdir/bfd/Makefile.am +index 5c5fdef..3c91651 100644 +--- binutils-clean/bfd/Makefile.am ++++ binutils-workdir/bfd/Makefile.am +@@ -778,7 +778,7 @@ ofiles: stamp-ofiles ; @true + libbfd_la_SOURCES = $(BFD32_LIBS_CFILES) + EXTRA_libbfd_la_SOURCES = $(CFILES) + libbfd_la_DEPENDENCIES = $(OFILES) ofiles ../libsframe/libsframe.la +-libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) ../libsframe/libsframe.la ++libbfd_la_LIBADD = `cat ofiles` @SHARED_LIBADD@ $(LIBDL) $(ZLIB) $(ZSTD_LIBS) $(SFRAME_LIB_PATH) ../libsframe/libsframe.la + libbfd_la_LDFLAGS += -release `cat libtool-soversion` @SHARED_LDFLAGS@ + + # This file holds an array associating configuration triplets and +diff --git binutils-clean/bfd/config.bfd binutils-workdir/bfd/config.bfd +index bdee539..48b2360 100644 +--- binutils-clean/bfd/config.bfd ++++ binutils-workdir/bfd/config.bfd +@@ -664,6 +664,11 @@ case "${targ}" in + targ_selvecs= + targ64_selvecs=x86_64_elf64_vec + ;; ++ i[3-7]86-*-aero*) ++ targ_defvec=i386_elf32_vec ++ targ_selvecs= ++ targ64_selvecs=x86_64_elf64_vec ++ ;; + #ifdef BFD64 + x86_64-*-cloudabi*) + targ_defvec=x86_64_elf64_cloudabi_vec +@@ -734,6 +739,11 @@ case "${targ}" in + targ_selvecs="i386_elf32_vec iamcu_elf32_vec x86_64_elf32_vec" + want64=true + ;; ++ x86_64-*-aero*) ++ targ_defvec=x86_64_elf64_vec ++ targ_selvecs=i386_elf32_vec ++ want64=true ++ ;; + #endif + i[3-7]86-*-lynxos*) + targ_defvec=i386_elf32_vec +diff --git binutils-clean/gas/configure.tgt binutils-workdir/gas/configure.tgt +index 3429f85..8fe03c1 100644 +--- binutils-clean/gas/configure.tgt ++++ binutils-workdir/gas/configure.tgt +@@ -227,6 +227,7 @@ case ${generic_target} in + i386-*-beos*) fmt=elf ;; + i386-*-elfiamcu) fmt=elf arch=iamcu ;; + i386-*-elf*) fmt=elf ;; ++ i386-*-aero*) fmt=elf em=gnu ;; + i386-*-fuchsia*) fmt=elf ;; + i386-*-haiku*) fmt=elf em=haiku ;; + i386-*-genode*) fmt=elf ;; +diff --git binutils-clean/gprofng/libcollector/configure.ac binutils-workdir/gprofng/libcollector/configure.ac +index 7af9581..c55e424 100644 +--- binutils-clean/gprofng/libcollector/configure.ac ++++ binutils-workdir/gprofng/libcollector/configure.ac +@@ -18,7 +18,7 @@ dnl . + + m4_include([../../bfd/version.m4]) + AC_INIT([gprofng], BFD_VERSION) +-AC_CONFIG_MACRO_DIRS([../../config ../..]) ++#AC_CONFIG_MACRO_DIRS([../../config ../..]) + AC_CONFIG_AUX_DIR(../..) + AC_CANONICAL_TARGET + AM_INIT_AUTOMAKE +diff --git binutils-clean/ld/configure.tgt binutils-workdir/ld/configure.tgt +index c62b958..3873c96 100644 +--- binutils-clean/ld/configure.tgt ++++ binutils-workdir/ld/configure.tgt +@@ -378,6 +378,9 @@ i[3-7]86-*-linux-*) targ_emul=elf_i386 + i[3-7]86-*-redox*) targ_emul=elf_i386 + targ_extra_emuls=elf_x86_64 + ;; ++i[3-7]86-*-aero*) targ_emul=elf_i386 ++ targ_extra_emuls=elf_x86_64 ++ ;; + i[3-7]86-*-solaris2*) targ_emul=elf_i386_sol2 + targ_extra_emuls="elf_i386_ldso elf_i386 elf_iamcu elf_x86_64_sol2 elf_x86_64" + targ_extra_libpath=$targ_extra_emuls +@@ -1011,6 +1014,9 @@ x86_64-*-linux-*) targ_emul=elf_x86_64 + x86_64-*-redox*) targ_emul=elf_x86_64 + targ_extra_emuls=elf_i386 + ;; ++x86_64-*-aero*) targ_emul=elf_x86_64 ++ targ_extra_emuls=elf_i386 ++ ;; + x86_64-*-solaris2*) targ_emul=elf_x86_64_sol2 + targ_extra_emuls="elf_x86_64 elf_i386_sol2 elf_i386_ldso elf_i386 elf_iamcu" + targ_extra_libpath=$targ_extra_emuls +diff --git binutils-clean/libiberty/configure.ac binutils-workdir/libiberty/configure.ac +index 0748c59..954e014 100644 +--- binutils-clean/libiberty/configure.ac ++++ binutils-workdir/libiberty/configure.ac +@@ -37,7 +37,7 @@ else + libiberty_topdir="${srcdir}/.." + fi + AC_SUBST(libiberty_topdir) +-AC_CONFIG_AUX_DIR($libiberty_topdir) ++AC_CONFIG_AUX_DIR([.]) + + dnl Very limited version of automake's enable-maintainer-mode + +diff --git binutils-workdir/multilib.am binutils-workdir/multilib.am +new file mode 100644 +index 0000000..5c98b69 +--- /dev/null ++++ binutils-workdir/multilib.am +@@ -0,0 +1,45 @@ ++## automake - create Makefile.in from Makefile.am ++ ++## Copyright (C) 1994-2017 Free Software Foundation, Inc. ++## This Makefile.in is free software; the Free Software Foundation ++## gives unlimited permission to copy and/or distribute it, ++## with or without modifications, as long as this notice is preserved. ++ ++## This program 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. ++ ++MULTISRCTOP = ++MULTIBUILDTOP = ++MULTIDIRS = ++MULTISUBDIR = ++MULTIDO = true ++MULTICLEAN = true ++ ++# GNU Make needs to see an explicit $(MAKE) variable in the command it ++# runs to enable its job server during parallel builds. Hence the ++# comments below. ++all-multi: ++ $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE) ++install-multi: ++ $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE) ++mostlyclean-multi: ++ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE) ++clean-multi: ++ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE) ++distclean-multi: ++ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE) ++maintainer-clean-multi: ++ $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE) ++ ++.MAKE .PHONY: all-multi clean-multi distclean-multi install-am \ ++ install-multi maintainer-clean-multi mostlyclean-multi ++ ++install-exec-local: install-multi ++ ++all-local: all-multi ++mostlyclean-local: mostlyclean-multi ++clean-local: clean-multi ++distclean-local: distclean-multi ++maintainer-clean-local: maintainer-clean-multi diff --git a/patches/cairo/jinx-working-patch.patch b/patches/cairo/jinx-working-patch.patch new file mode 100644 index 00000000000..accf74eb94a --- /dev/null +++ b/patches/cairo/jinx-working-patch.patch @@ -0,0 +1,33 @@ +diff --git cairo-clean/meson.build cairo-workdir/meson.build +index 9100152..1b7e91d 100644 +--- cairo-clean/meson.build ++++ cairo-workdir/meson.build +@@ -374,18 +374,18 @@ if x11_dep.found() and xext_dep.found() + # between a set value (bool) or the fallback value (string), so convert to + # a string and check the string value. + prop_str = '@0@'.format(prop) +- if prop_str in ['true', 'false'] ++ #if prop_str in ['true', 'false'] + ipc_rmid_deferred_release = (prop_str == 'true') + message('IPC_RMID_DEFERRED_RELEASE:', ipc_rmid_deferred_release) +- elif prop_str == 'auto' +- res = cc.run(files('meson-cc-tests/ipc_rmid_deferred_release.c'), +- dependencies: [x11_dep, xext_dep], +- name: 'shmctl IPC_RMID allowes subsequent attaches') +- +- ipc_rmid_deferred_release = (res.returncode() == 0) +- else +- error('Unexpected value for external property ipc_rmid_deferred_release: @0@'.format(prop_str)) +- endif ++ #elif prop_str == 'auto' ++ # res = cc.run(files('meson-cc-tests/ipc_rmid_deferred_release.c'), ++ # dependencies: [x11_dep, xext_dep], ++ # name: 'shmctl IPC_RMID allowes subsequent attaches') ++ ++ # ipc_rmid_deferred_release = (res.returncode() == 0) ++ #else ++ # error('Unexpected value for external property ipc_rmid_deferred_release: @0@'.format(prop_str)) ++ #endif + + conf.set10('IPC_RMID_DEFERRED_RELEASE', ipc_rmid_deferred_release) + endif diff --git a/patches/coreutils/coreutils.patch b/patches/coreutils/coreutils.patch deleted file mode 100644 index da878672fc8..00000000000 --- a/patches/coreutils/coreutils.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/bundled/coreutils-orig/build-aux/config.sub b/bundled/coreutils-workdir/build-aux/config.sub -index f02d43a..06e0dab 100755 ---- a/bundled/coreutils-orig/build-aux/config.sub -+++ b/bundled/coreutils-workdir/build-aux/config.sub -@@ -1346,7 +1346,7 @@ case $os in - | aos* | aros* | cloudabi* | sortix* | twizzler* \ - | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ - | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ -- | knetbsd* | mirbsd* | netbsd* \ -+ | knetbsd* | mirbsd* | netbsd* | aero* \ - | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \ - | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ - | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ \ No newline at end of file diff --git a/patches/dbus/jinx-working-patch.patch b/patches/dbus/jinx-working-patch.patch new file mode 100644 index 00000000000..2daea44cafa --- /dev/null +++ b/patches/dbus/jinx-working-patch.patch @@ -0,0 +1,13 @@ +diff --git dbus-clean/dbus/dbus-sysdeps-unix.c dbus-workdir/dbus/dbus-sysdeps-unix.c +index dbc459c..6a3e851 100644 +--- dbus-clean/dbus/dbus-sysdeps-unix.c ++++ dbus-workdir/dbus/dbus-sysdeps-unix.c +@@ -4896,7 +4896,7 @@ _dbus_check_setuid (void) + + if (_DBUS_UNLIKELY (!check_setuid_initialised)) + { +-#ifdef HAVE_GETRESUID ++#if defined HAVE_GETRESUID && !defined(__aero__) + if (getresuid (&ruid, &euid, &suid) != 0 || + getresgid (&rgid, &egid, &sgid) != 0) + #endif /* HAVE_GETRESUID */ diff --git a/patches/doomgeneric/doomgeneric.patch b/patches/doomgeneric/doomgeneric.patch deleted file mode 100644 index 9ccc4902af4..00000000000 --- a/patches/doomgeneric/doomgeneric.patch +++ /dev/null @@ -1,664 +0,0 @@ -From fe158557671423437d813cf623ca1997d498dc19 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Sat, 15 Jan 2022 18:07:32 +1100 -Subject: [PATCH] add aero doom - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 9 ++ - doomgeneric/Makefile.aero | 80 ++++++++++ - doomgeneric/aero/framebuffer.h | 243 ++++++++++++++++++++++++++++++ - doomgeneric/d_main.c | 4 + - doomgeneric/doomgeneric_aero.c | 266 +++++++++++++++++++++++++++++++++ - 5 files changed, 602 insertions(+) - create mode 100644 .gitignore - create mode 100644 doomgeneric/Makefile.aero - create mode 100644 doomgeneric/aero/framebuffer.h - create mode 100644 doomgeneric/doomgeneric_aero.c - -diff --git a/.gitignore b/.gitignore -new file mode 100644 -index 0000000..e610a33 ---- /dev/null -+++ b/.gitignore -@@ -0,0 +1,9 @@ -+build -+ -+doomgeneric/doomgeneric -+doomgeneric/doomgeneric.map -+ -+doom1.wad -+ -+.vscode -+.clang-format -diff --git a/doomgeneric/Makefile.aero b/doomgeneric/Makefile.aero -new file mode 100644 -index 0000000..3cde87c ---- /dev/null -+++ b/doomgeneric/Makefile.aero -@@ -0,0 +1,80 @@ -+################################################################ -+# -+# $Id:$ -+# -+# $Log:$ -+# -+ -+# Copyright (C) 2021-2022 The Aero Project Developers. -+# -+# This file is part of The Aero Project. -+# -+# Aero 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 of the License, or -+# (at your option) any later version. -+# -+# Aero 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. -+# -+# You should have received a copy of the GNU General Public License -+# along with Aero. If not, see . -+ -+ifeq ($(V),1) -+ VB='' -+else -+ VB=@ -+endif -+ -+CC=x86_64-aero-gcc -+ -+CFLAGS+=-O0 -g -+LDFLAGS+=-Wl,--gc-sections -+CFLAGS+=-Wall -DNORMALUNIX -DLINUX -DSNDSERV -D_DEFAULT_SOURCE -+ -+LIBS+=-lm -lc -+ -+OBJDIR=build -+OUTPUT=doomgeneric -+ -+SRC_DOOM = i_main.o dummy.o am_map.o doomdef.o doomstat.o dstrings.o d_event.o \ -+ d_items.o d_iwad.o d_loop.o d_main.o d_mode.o d_net.o f_finale.o f_wipe.o \ -+ g_game.o hu_lib.o hu_stuff.o info.o i_cdmus.o i_endoom.o i_joystick.o i_scale.o \ -+ i_sound.o i_system.o i_timer.o memio.o m_argv.o m_bbox.o m_cheat.o m_config.o \ -+ m_controls.o m_fixed.o m_menu.o m_misc.o m_random.o p_ceilng.o p_doors.o p_enemy.o \ -+ p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o \ -+ p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o \ -+ r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o sha1.o \ -+ sounds.o statdump.o st_lib.o st_stuff.o s_sound.o tables.o v_video.o wi_stuff.o \ -+ w_checksum.o w_file.o w_main.o w_wad.o z_zone.o w_file_stdc.o i_input.o i_video.o \ -+ doomgeneric.o doomgeneric_aero.o -+ -+OBJS += $(addprefix $(OBJDIR)/, $(SRC_DOOM)) -+ -+all: $(OUTPUT) -+ -+clean: -+ rm -rf $(OBJDIR) -+ rm -f $(OUTPUT) -+ rm -f $(OUTPUT).gdb -+ rm -f $(OUTPUT).map -+ -+$(OUTPUT): $(OBJS) -+ @echo [Linking $@] -+ -+ $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) \ -+ -o $(OUTPUT) $(LIBS) -Wl,-Map,$(OUTPUT).map -+ -+ @echo [Size] -+ -$(CROSS_COMPILE)size $(OUTPUT) -+ -+$(OBJS): | $(OBJDIR) -+ -+$(OBJDIR): -+ mkdir -p $(OBJDIR) -+ -+$(OBJDIR)/%.o: %.c -+ @echo [Compiling $<] -+ $(VB)$(CC) $(CFLAGS) -c $< -o $@ -diff --git a/doomgeneric/aero/framebuffer.h b/doomgeneric/aero/framebuffer.h -new file mode 100644 -index 0000000..6d195f0 ---- /dev/null -+++ b/doomgeneric/aero/framebuffer.h -@@ -0,0 +1,243 @@ -+#ifndef _AERO_FB_H_ -+#define _AERO_FB_H_ -+ -+#include -+#include -+ -+#define FB_MAX 32 -+ -+#define FBIOGET_VSCREENINFO 0x4600 -+#define FBIOPUT_VSCREENINFO 0x4601 -+#define FBIOGET_FSCREENINFO 0x4602 -+#define FBIOGETCMAP 0x4604 -+#define FBIOPUTCMAP 0x4605 -+#define FBIOPAN_DISPLAY 0x4606 -+#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) -+ -+#define FBIOGET_CON2FBMAP 0x460F -+#define FBIOPUT_CON2FBMAP 0x4610 -+#define FBIOBLANK 0x4611 -+#define FBIOGET_VBLANK _IOWR('F', 0x12, struct fb_vblank) -+#define FBIO_ALLOC 0x4613 -+#define FBIO_FREE 0x4614 -+#define FBIOGET_GLYPH 0x4615 -+#define FBIOGET_HWCINFO 0x4616 -+#define FBIOPUT_MODEINFO 0x4617 -+#define FBIOGET_DISPINFO 0x4618 -+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, unsigned int) -+ -+#define FB_TYPE_PACKED_PIXELS 0 -+#define FB_TYPE_PLANES 1 -+#define FB_TYPE_INTERLEAVED_PLANES 2 -+#define FB_TYPE_TEXT 3 -+#define FB_TYPE_VGA_PLANES 4 -+#define FB_TYPE_FOURCC 5 -+ -+#define FB_VISUAL_MONO01 0 -+#define FB_VISUAL_MONO10 1 -+#define FB_VISUAL_TRUECOLOR 2 -+#define FB_VISUAL_PSEUDOCOLOR 3 -+#define FB_VISUAL_DIRECTCOLOR 4 -+#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 -+#define FB_VISUAL_FOURCC 6 -+ -+#define FB_ACCEL_NONE 0 -+ -+#define FB_NONSTD_HAM 1 -+#define FB_NONSTD_REV_PIX_IN_B 2 -+ -+#define FB_ACTIVATE_NOW 0 -+#define FB_ACTIVATE_NXTOPEN 1 -+#define FB_ACTIVATE_TEST 2 -+#define FB_ACTIVATE_MASK 15 -+ -+#define FB_ACTIVATE_VBL 16 -+#define FB_CHANGE_CMAP 32 -+#define FB_ACTIVATE_ALL 64 -+#define FB_ACTIVATE_FORCE 128 -+#define FB_ACTIVATE_INV_MODE 256 -+#define FB_ACTIVATE_INV_ALL 512 -+ -+#define FB_ACCELF_TEXT 0x1 -+ -+#define FB_SYNC_HOR_HIGH_ACT 0x1 -+#define FB_SYNC_VERT_HIGH_ACT 0x2 -+#define FB_SYNC_EXT 0x4 -+#define FB_SYNC_COMP_HIGH_ACT 0x8 -+#define FB_SYNC_BROADCAST 0x10 -+#define FB_SYNC_ON_GREEN 0x20 -+ -+#define FB_VMODE_NONINTERLACED 0 -+#define FB_VMODE_INTERLACED 1 -+#define FB_VMODE_DOUBLE 2 -+#define FB_VMODE_ODD_FLD_FIRST 4 -+#define FB_VMODE_MASK 255 -+ -+#define FB_VMODE_YWRAP 256 -+#define FB_VMODE_SMOOTH_XPAN 512 -+#define FB_VMODE_CONUPDATE 512 -+ -+#define FB_ROTATE_UR 0 -+#define FB_ROTATE_CW 1 -+#define FB_ROTATE_UD 2 -+#define FB_ROTATE_CCW 3 -+ -+#define PICOS2KHZ(a) (1000000000UL/(a)) -+#define KHZ2PICOS(a) (1000000000UL/(a)) -+ -+#define VESA_NO_BLANKING 0 -+#define VESA_VSYNC_SUSPEND 1 -+#define VESA_HSYNC_SUSPEND 2 -+#define VESA_POWERDOWN 3 -+ -+enum { -+ FB_BLANK_UNBLANK = VESA_NO_BLANKING, -+ FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, -+ FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, -+ FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, -+ FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1, -+}; -+ -+#define FB_VBLANK_VBLANKING 0x001 -+#define FB_VBLANK_HBLANKING 0x002 -+#define FB_VBLANK_HAVE_VBLANK 0x004 -+#define FB_VBLANK_HAVE_HBLANK 0x008 -+#define FB_VBLANK_HAVE_COUNT 0x010 -+#define FB_VBLANK_HAVE_VCOUNT 0x020 -+#define FB_VBLANK_HAVE_HCOUNT 0x040 -+#define FB_VBLANK_VSYNCING 0x080 -+#define FB_VBLANK_HAVE_VSYNC 0x100 -+ -+#define ROP_COPY 0 -+#define ROP_XOR 1 -+ -+#define FB_CUR_SETIMAGE 0x01 -+#define FB_CUR_SETPOS 0x02 -+#define FB_CUR_SETHOT 0x04 -+#define FB_CUR_SETCMAP 0x08 -+#define FB_CUR_SETSHAPE 0x10 -+#define FB_CUR_SETSIZE 0x20 -+#define FB_CUR_SETALL 0xFF -+ -+struct fb_fix_screeninfo { -+ char id[16]; -+ unsigned long smem_start; -+ unsigned int smem_len; -+ unsigned int type; -+ unsigned int type_aux; -+ unsigned int visual; -+ unsigned short xpanstep; -+ unsigned short ypanstep; -+ unsigned short ywrapstep; -+ unsigned int line_length; -+ unsigned long mmio_start; -+ unsigned int mmio_len; -+ unsigned int accel; -+ unsigned short capabilities; -+ unsigned short reserved[2]; -+}; -+ -+struct fb_bitfield { -+ unsigned int offset; -+ unsigned int length; -+ unsigned int msb_right; -+}; -+ -+struct fb_var_screeninfo { -+ unsigned int xres; -+ unsigned int yres; -+ unsigned int xres_virtual; -+ unsigned int yres_virtual; -+ unsigned int xoffset; -+ unsigned int yoffset; -+ unsigned int bits_per_pixel; -+ unsigned int grayscale; -+ struct fb_bitfield red; -+ struct fb_bitfield green; -+ struct fb_bitfield blue; -+ struct fb_bitfield transp; -+ unsigned int nonstd; -+ unsigned int activate; -+ unsigned int height; -+ unsigned int width; -+ unsigned int accel_flags; -+ unsigned int pixclock; -+ unsigned int left_margin; -+ unsigned int right_margin; -+ unsigned int upper_margin; -+ unsigned int lower_margin; -+ unsigned int hsync_len; -+ unsigned int vsync_len; -+ unsigned int sync; -+ unsigned int vmode; -+ unsigned int rotate; -+ unsigned int colorspace; -+ unsigned int reserved[4]; -+}; -+ -+struct fb_cmap { -+ unsigned int start; -+ unsigned int len; -+ unsigned short *red; -+ unsigned short *green; -+ unsigned short *blue; -+ unsigned short *transp; -+}; -+ -+struct fb_con2fbmap { -+ unsigned int console; -+ unsigned int framebuffer; -+}; -+ -+struct fb_vblank { -+ unsigned int flags; -+ unsigned int count; -+ unsigned int vcount; -+ unsigned int hcount; -+ unsigned int reserved[4]; -+}; -+ -+struct fb_copyarea { -+ unsigned int dx; -+ unsigned int dy; -+ unsigned int width; -+ unsigned int height; -+ unsigned int sx; -+ unsigned int sy; -+}; -+ -+struct fb_fillrect { -+ unsigned int dx; -+ unsigned int dy; -+ unsigned int width; -+ unsigned int height; -+ unsigned int color; -+ unsigned int rop; -+}; -+ -+struct fb_image { -+ unsigned int dx; -+ unsigned int dy; -+ unsigned int width; -+ unsigned int height; -+ unsigned int fg_color; -+ unsigned int bg_color; -+ unsigned char depth; -+ const char *data; -+ struct fb_cmap cmap; -+}; -+ -+struct fbcurpos { -+ unsigned short x, y; -+}; -+ -+struct fb_cursor { -+ unsigned short set; -+ unsigned short enable; -+ unsigned short rop; -+ const char *mask; -+ struct fbcurpos hot; -+ struct fb_image image; -+}; -+ -+#endif // _AERO_FB_H_ -diff --git a/doomgeneric/d_main.c b/doomgeneric/d_main.c -index c7cf977..435e76a 100644 ---- a/doomgeneric/d_main.c -+++ b/doomgeneric/d_main.c -@@ -1357,12 +1357,16 @@ void D_DoomMain (void) - D_BindVariables(); - M_LoadDefaults(); - -+ DEH_printf("I_AtExit: Installing handler to save config at exit.\n"); -+ - // Save configuration at exit. - I_AtExit(M_SaveDefaults, false); - -+ DEH_printf("D_FindIWAD: Searching for the IWAD file.\n"); - // Find main IWAD file and load it. - iwadfile = D_FindIWAD(IWAD_MASK_DOOM, &gamemission); - -+ - // None found? - - if (iwadfile == NULL) -diff --git a/doomgeneric/doomgeneric_aero.c b/doomgeneric/doomgeneric_aero.c -new file mode 100644 -index 0000000..1172db3 ---- /dev/null -+++ b/doomgeneric/doomgeneric_aero.c -@@ -0,0 +1,266 @@ -+/* -+ * Copyright (C) 2021-2022 The Aero Project Developers. -+ * -+ * This file is part of The Aero Project. -+ * -+ * Aero 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 of the License, or -+ * (at your option) any later version. -+ * -+ * Aero 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. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Aero. If not, see . -+ */ -+ -+#include "doomgeneric.h" -+#include "doomkeys.h" -+ -+#include "aero/framebuffer.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define LOG_INFO 0 -+#define KEYBOARD_QUEUE_SIZE 16 -+ -+FILE *keyboard = NULL; -+ -+static uint32_t *framebuffer_ptr = NULL; -+ -+static uint32_t s_screen_width = 0; -+static uint32_t s_screen_height = 0; -+ -+static uint32_t s_position_x = 0; -+static uint32_t s_position_y = 0; -+ -+static uint16_t s_key_queue[KEYBOARD_QUEUE_SIZE]; -+static uint32_t s_key_queue_write_idx = 0; -+static uint32_t s_key_queue_read_idx = 0; -+ -+static void log_info(char *message, ...) { -+#ifdef LOG_INFO -+ va_list args; -+ va_start(args, message); -+ printf("\x1b[1;32minfo\x1b[0m: "); -+ vprintf(message, args); -+ printf("\n"); -+ va_end(args); -+ fflush(stdout); -+#endif -+} -+ -+static void log_error(char *message) { -+ printf("\x1b[1;31minfo\x1b[0m: %s\n", message); -+ fflush(stdout); -+} -+ -+struct termios orig_termios; -+ -+/// Disables raw TTY mode. -+static void disable_raw_tty() { -+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); -+} -+ -+/// Enables raw TTY mode. -+/// -+/// SAFTEY: Remember to disable raw tty mode on exit. -+static void enable_raw_tty() { -+ tcgetattr(STDIN_FILENO, &orig_termios); -+ -+ struct termios raw = orig_termios; -+ raw.c_lflag &= ~(ECHO | ICANON); -+ raw.c_cc[VMIN] = 0; -+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); -+} -+ -+/// Converts an aero scancode into doom scancode. -+static uint8_t convert_to_doom_key(uint8_t scancode) { -+ uint8_t key = 0; -+ -+ switch (scancode) { -+ case 28: // enter -+ key = KEY_ENTER; -+ break; -+ -+ case 1: // escape -+ key = KEY_ESCAPE; -+ break; -+ -+ case 105: // left -+ key = KEY_LEFTARROW; -+ break; -+ -+ case 106: // right -+ key = KEY_RIGHTARROW; -+ break; -+ -+ case 103: // up -+ key = KEY_UPARROW; -+ break; -+ -+ case 108: // down -+ key = KEY_DOWNARROW; -+ break; -+ -+ case 29: // left control -+ case 97: // right control -+ key = KEY_FIRE; -+ break; -+ -+ case 57: // spacebar -+ key = KEY_USE; -+ break; -+ -+ case 54: // rightshift -+ key = KEY_RSHIFT; -+ break; -+ -+ case 21: // y -+ key = 'y'; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return key; -+} -+ -+/// Pushes a key into the keyboard queue. -+static void push_key_to_queue(uint8_t pressed, uint8_t key_code) { -+ uint8_t key = convert_to_doom_key(key_code); -+ uint16_t key_data = (pressed << 8) | key; -+ -+ s_key_queue[s_key_queue_write_idx] = key_data; -+ s_key_queue_write_idx += 1; -+ s_key_queue_write_idx %= KEYBOARD_QUEUE_SIZE; -+} -+ -+/// Handle the keyboard input and put it into the key queue. -+static void handle_keyboard_input() { -+ // SAFTEY: `/dev/kbd0` is non-blocking. -+ uint8_t scancode = 0; -+ size_t result = read(fileno(keyboard), &scancode, 1); -+ -+ if (result > 0) { -+ uint8_t key_released = (0x80 & scancode); -+ scancode = (0x7F & scancode); -+ -+ if (key_released == 0) -+ push_key_to_queue(1, scancode); -+ else { -+ push_key_to_queue(0, scancode); -+ } -+ } -+} -+ -+/// Initialize doomgeneric. This includes setting up the framebuffer and -+/// keyboard devices. -+void DG_Init() { -+ log_info("initializing framebuffer"); -+ -+ // Open up the framebuffer device. -+ size_t framebuffer = fopen("/dev/fb0", "r+"); -+ -+ // Make sure the there were no errors. -+ if (framebuffer == NULL) { -+ log_error("failed to open `/dev/fb0`"); -+ exit(1); -+ } -+ -+ // Get the framebuffer info. -+ struct fb_var_screeninfo vinfo; -+ int result = ioctl(fileno(framebuffer), FBIOGET_VSCREENINFO, &vinfo); -+ -+ // Make sure the ioctl was successful. -+ if (result) { -+ log_error("failed to get framebuffer vscreen info"); -+ exit(1); -+ } -+ -+ s_screen_width = vinfo.xres; -+ s_screen_height = vinfo.yres; -+ -+ log_info("framebuffer: (width=%lu, height=%lu)", (uint64_t)s_screen_width, -+ (uint64_t)s_screen_height); -+ -+ s_position_x = (s_screen_width - DOOMGENERIC_RESX) / 2; -+ s_position_y = (s_screen_height - DOOMGENERIC_RESY) / 2; -+ -+ uint32_t size = s_screen_width * s_screen_height * vinfo.bits_per_pixel / 8; -+ framebuffer_ptr = (uint32_t *)mmap(NULL, size, PROT_READ | PROT_WRITE, -+ MAP_SHARED, fileno(framebuffer), 0); -+ -+ enable_raw_tty(); -+ atexit(disable_raw_tty); -+ -+ // Open the keyboard device. -+ keyboard = fopen("/dev/kbd0", "r"); -+ -+ // Make sure the there were no errors. -+ if (keyboard == NULL) { -+ log_error("failed to open `/dev/kbd0`"); -+ exit(1); -+ } -+ -+ log_info("successfuly initialized doomgeneric"); -+} -+ -+void DG_DrawFrame() { -+ for (int i = 0; i < DOOMGENERIC_RESY; i++) { -+ size_t index = s_position_x + (i + s_position_y) * s_screen_width; -+ size_t count = DOOMGENERIC_RESX * 4; -+ -+ uint32_t *dest_ptr = &framebuffer_ptr[index]; -+ uint32_t *src_ptr = DG_ScreenBuffer + i * DOOMGENERIC_RESX; -+ -+ memcpy(dest_ptr, src_ptr, count); -+ } -+ -+ handle_keyboard_input(); -+} -+ -+void DG_SleepMs(uint32_t ms) { usleep(ms * 1000); } -+ -+uint32_t DG_GetTicksMs() { -+ struct timeval tp; -+ struct timezone tzp; -+ -+ gettimeofday(&tp, &tzp); -+ -+ return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); -+} -+ -+int DG_GetKey(int *pressed, unsigned char *doomKey) { -+ // The key queue is empty. -+ if (s_key_queue_write_idx == s_key_queue_read_idx) { -+ return 0; -+ } -+ -+ uint16_t key_data = s_key_queue[s_key_queue_read_idx]; -+ s_key_queue_read_idx += 1; -+ s_key_queue_read_idx %= KEYBOARD_QUEUE_SIZE; -+ -+ *pressed = key_data >> 8; -+ *doomKey = key_data & 0xFF; -+ -+ return 1; -+} -+ -+// NOTE: We dont need to set the window title :) -+void DG_SetWindowTitle(const char *title) {} --- -2.25.1 - diff --git a/patches/fontconfig/jinx-working-patch.patch b/patches/fontconfig/jinx-working-patch.patch new file mode 100644 index 00000000000..b1816e93eeb --- /dev/null +++ b/patches/fontconfig/jinx-working-patch.patch @@ -0,0 +1,13 @@ +diff --git fontconfig-clean/src/fcstat.c fontconfig-workdir/src/fcstat.c +index 4f69eae..519cf1d 100644 +--- fontconfig-clean/src/fcstat.c ++++ fontconfig-workdir/src/fcstat.c +@@ -386,7 +386,7 @@ FcFStatFs (int fd, FcStatFS *statb) + # endif + # if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) + p = buf.f_fstypename; +-# elif defined(__linux__) || defined (__EMSCRIPTEN__) ++# elif defined(__linux__) || defined (__aero__) || defined (__EMSCRIPTEN__) + switch (buf.f_type) + { + case 0x6969: /* nfs */ diff --git a/patches/fox/jinx-working-patch.patch b/patches/fox/jinx-working-patch.patch new file mode 100644 index 00000000000..a163bd5781a --- /dev/null +++ b/patches/fox/jinx-working-patch.patch @@ -0,0 +1,41 @@ +diff --git fox-clean/configure.ac fox-workdir/configure.ac +index ce0f651..189b5e8 100644 +--- fox-clean/configure.ac ++++ fox-workdir/configure.ac +@@ -9,6 +9,8 @@ AC_INIT(fox,[fox_version],jeroen@fox-toolkit.com) + AC_CONFIG_SRCDIR([include/fx.h]) + AM_INIT_AUTOMAKE([foreign]) + ++PKG_PROG_PKG_CONFIG ++ + # Set version + FOX_MAJOR_VERSION=fox_major + FOX_MINOR_VERSION=fox_minor +@@ -190,8 +192,8 @@ AC_MSG_CHECKING(for Xft support) + AC_ARG_WITH(xft,[ --with-xft enable Xft support]) + AC_MSG_RESULT([$with_xft]) + if test "x$with_xft" != "xno"; then +-XFTCFLAGS="-I/usr/include/freetype2" +-XFTLIBS="-lfreetype -lfontconfig -lXft" ++XFTCFLAGS="$($PKG_CONFIG --cflags freetype2 fontconfig xft)" ++XFTLIBS="$($PKG_CONFIG --libs freetype2 fontconfig xft)" + saved_cppflags="${CXXFLAGS}" + CXXFLAGS="${CXXFLAGS} -DHAVE_XFT_H=1 $XFTCFLAGS" + X_BASE_LIBS="${X_BASE_LIBS} $XFTLIBS" +diff --git fox-clean/include/FXStream.h fox-workdir/include/FXStream.h +index 41fe97a..b483556 100644 +--- fox-clean/include/FXStream.h ++++ fox-workdir/include/FXStream.h +@@ -52,9 +52,9 @@ enum FXStreamStatus { + + /// Stream seeking + enum FXWhence { +- FXFromStart=0, /// Seek from start position +- FXFromCurrent=1, /// Seek from current position +- FXFromEnd=2 /// Seek from end position ++ FXFromStart=3, /// Seek from start position (SEEK_SET) ++ FXFromCurrent=1, /// Seek from current position (SEEK_CUR) ++ FXFromEnd=2 /// Seek from end position (SEEK_END) + }; + + diff --git a/patches/gcc-host/jinx-working-patch.patch b/patches/gcc-host/jinx-working-patch.patch new file mode 100644 index 00000000000..d280068ea5f --- /dev/null +++ b/patches/gcc-host/jinx-working-patch.patch @@ -0,0 +1,153 @@ +diff --git gcc-host-clean/fixincludes/mkfixinc.sh gcc-host-workdir/fixincludes/mkfixinc.sh +index df90720..da6408a 100755 +--- gcc-host-clean/fixincludes/mkfixinc.sh ++++ gcc-host-workdir/fixincludes/mkfixinc.sh +@@ -12,6 +12,7 @@ target=fixinc.sh + # Check for special fix rules for particular targets + case $machine in + i?86-*-cygwin* | \ ++ x86_64-*-aero* | \ + i?86-*-mingw32* | \ + x86_64-*-mingw32* | \ + powerpc-*-eabisim* | \ +diff --git gcc-host-workdir/gcc/config/aero.h gcc-host-workdir/gcc/config/aero.h +new file mode 100644 +index 0000000..be79aae +--- /dev/null ++++ gcc-host-workdir/gcc/config/aero.h +@@ -0,0 +1,29 @@ ++#undef TARGET_AERO ++#define TARGET_AERO 1 ++ ++#undef LIB_SPEC ++#define LIB_SPEC "-lc" ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC "%{!shared:crt0.o%s} crti.o%s %{shared:crtbeginS.o%s;:crtbegin.o%s}" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC "%{shared:crtendS.o%s;:crtend.o%s} crtn.o%s" ++ ++#define GNU_USER_LINK_EMULATION32 "elf_i386" ++#define GNU_USER_LINK_EMULATION64 "elf_x86_64" ++#define GNU_USER_LINK_EMULATIONX32 "elf32_x86_64" ++ ++#define GNU_USER_DYNAMIC_LINKER32 "/usr/lib/ld_i386.so" ++#define GNU_USER_DYNAMIC_LINKER64 "/usr/lib/ld.so" ++#define GNU_USER_DYNAMIC_LINKERX32 "/usr/lib/ld32.so" ++ ++#undef TARGET_OS_CPP_BUILTINS ++#define TARGET_OS_CPP_BUILTINS() \ ++ do { \ ++ builtin_define ("__aero__"); \ ++ builtin_define ("__unix__"); \ ++ builtin_assert ("system=aero"); \ ++ builtin_assert ("system=unix"); \ ++ builtin_assert ("system=posix"); \ ++ } while (0); +diff --git gcc-host-clean/gcc/config.gcc gcc-host-workdir/gcc/config.gcc +index 648b3dc..f2b0217 100644 +--- gcc-host-clean/gcc/config.gcc ++++ gcc-host-workdir/gcc/config.gcc +@@ -840,6 +840,15 @@ case ${target} in + tmake_file="${tmake_file} t-freebsd" + target_has_targetdm=yes + ;; ++*-*-aero*) ++ extra_options="$extra_options gnu-user.opt" ++ gas=yes ++ gnu_ld=yes ++ default_use_cxa_atexit=yes ++ use_gcc_stdint=wrap ++ tmake_file="${tmake_file} t-slibgcc" ++ thread_file='posix' ++ ;; + *-*-fuchsia*) + native_system_header_dir=/include + ;; +@@ -2214,6 +2223,9 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) + ;; + esac + ;; ++x86_64-*-aero*) ++ tm_file="${tm_file} i386/unix.h i386/att.h elfos.h gnu-user.h glibc-stdint.h i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h aero.h" ++ ;; + x86_64-*-fuchsia*) + tmake_file="${tmake_file} i386/t-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 fuchsia.h" +diff --git gcc-host-clean/libgcc/config.host gcc-host-workdir/libgcc/config.host +index 9d72120..b4e90ab 100644 +--- gcc-host-clean/libgcc/config.host ++++ gcc-host-workdir/libgcc/config.host +@@ -281,6 +281,11 @@ case ${host} in + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-fuchsia" + extra_parts="crtbegin.o crtend.o" + ;; ++*-*-aero*) ++ extra_parts="$extra_parts crti.o crtbegin.o crtbeginS.o crtend.o crtendS.o crtn.o" ++ tmake_file="$tmake_file t-crtstuff-pic" ++ tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-libgcc-pic" ++ ;; + *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu | *-*-uclinuxfdpiceabi) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux" + extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" +@@ -715,6 +720,10 @@ x86_64-*-elf* | x86_64-*-rtems*) + x86_64-*-fuchsia*) + tmake_file="$tmake_file t-libgcc-pic" + ;; ++x86_64-*-aero*) ++ extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" ++ tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" ++ ;; + i[34567]86-*-dragonfly*) + tmake_file="${tmake_file} i386/t-dragonfly i386/t-crtstuff" + md_unwind_header=i386/dragonfly-unwind.h +diff --git gcc-host-clean/libgcc/configure.ac gcc-host-workdir/libgcc/configure.ac +index 2fc9d5d..83d246e 100644 +--- gcc-host-clean/libgcc/configure.ac ++++ gcc-host-workdir/libgcc/configure.ac +@@ -46,7 +46,7 @@ else + libgcc_topdir="${srcdir}/.." + fi + AC_SUBST(libgcc_topdir) +-AC_CONFIG_AUX_DIR($libgcc_topdir) ++AC_CONFIG_AUX_DIR([.]) + AC_CONFIG_HEADER(auto-target.h:config.in) + + AC_ARG_ENABLE(shared, +diff --git gcc-host-clean/libiberty/configure.ac gcc-host-workdir/libiberty/configure.ac +index 28d996f..61ff752 100644 +--- gcc-host-clean/libiberty/configure.ac ++++ gcc-host-workdir/libiberty/configure.ac +@@ -37,7 +37,7 @@ else + libiberty_topdir="${srcdir}/.." + fi + AC_SUBST(libiberty_topdir) +-AC_CONFIG_AUX_DIR($libiberty_topdir) ++AC_CONFIG_AUX_DIR([.]) + + dnl Very limited version of automake's enable-maintainer-mode + +diff --git gcc-host-clean/libstdc++-v3/crossconfig.m4 gcc-host-workdir/libstdc++-v3/crossconfig.m4 +index b3269cb..a1d4a28 100644 +--- gcc-host-clean/libstdc++-v3/crossconfig.m4 ++++ gcc-host-workdir/libstdc++-v3/crossconfig.m4 +@@ -136,6 +136,18 @@ case "${host}" in + AC_CHECK_FUNCS(uselocale) + ;; + ++ *-aero*) ++ GLIBCXX_CHECK_COMPILER_FEATURES ++ GLIBCXX_CHECK_LINKER_FEATURES ++ GLIBCXX_CHECK_MATH_SUPPORT ++ GLIBCXX_CHECK_STDLIB_SUPPORT ++ AC_DEFINE(_GLIBCXX_USE_DEV_RANDOM) ++ AC_DEFINE(_GLIBCXX_USE_RANDOM_TR1) ++ GCC_CHECK_TLS ++ AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) ++ AC_CHECK_FUNCS(timespec_get) ++ ;; ++ + *-fuchsia*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' + AC_SUBST(SECTION_FLAGS) diff --git a/patches/gcc/gcc.patch b/patches/gcc/gcc.patch deleted file mode 100644 index f019b16f297..00000000000 --- a/patches/gcc/gcc.patch +++ /dev/null @@ -1,226 +0,0 @@ -From dee75c7161a4ffc5760f7615ed7846a9592bc77c Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Tue, 31 Aug 2021 11:02:13 +1000 -Subject: [PATCH] targets: add aero target port - -Signed-off-by: Andy-Python-Programmer ---- - .vscode/settings.json | 3 +++ - config.sub | 4 ++-- - fixincludes/mkfixinc.sh | 1 + - gcc/config.gcc | 12 ++++++++++++ - gcc/config/aero.h | 30 ++++++++++++++++++++++++++++++ - libgcc/config.host | 8 ++++++++ - libgcc/libgcov.h | 1 + - libstdc++-v3/crossconfig.m4 | 12 ++++++++++++ - libtool.m4 | 14 ++++++++++++++ - 9 files changed, 83 insertions(+), 2 deletions(-) - create mode 100644 .vscode/settings.json - create mode 100644 gcc/config/aero.h - -diff --git a/.vscode/settings.json b/.vscode/settings.json -new file mode 100644 -index 000000000..560faaa36 ---- /dev/null -+++ b/.vscode/settings.json -@@ -0,0 +1,3 @@ -+{ -+ "editor.formatOnSave": false, -+} -\ No newline at end of file -diff --git a/config.sub b/config.sub -index 63c1f1c8b..36fff07fb 100755 ---- a/config.sub -+++ b/config.sub -@@ -133,7 +133,7 @@ case $1 in - case $maybe_os in - nto-qnx* | linux-* | uclinux-uclibc* \ - | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ -- | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ -+ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* | aero* \ - | storm-chaos* | os2-emx* | rtmk-nova*) - basic_machine=$field1 - basic_os=$maybe_os -@@ -1723,7 +1723,7 @@ case $os in - | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \ - | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ - | skyos* | haiku* | rdos* | toppers* | drops* | es* \ -- | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ -+ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | aero* | bme* \ - | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ - | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*) - ;; -diff --git a/fixincludes/mkfixinc.sh b/fixincludes/mkfixinc.sh -index df90720b7..e8c2b21c1 100755 ---- a/fixincludes/mkfixinc.sh -+++ b/fixincludes/mkfixinc.sh -@@ -11,6 +11,7 @@ target=fixinc.sh - - # Check for special fix rules for particular targets - case $machine in -+ x86_64-*-aero* | \ - i?86-*-cygwin* | \ - i?86-*-mingw32* | \ - x86_64-*-mingw32* | \ -diff --git a/gcc/config.gcc b/gcc/config.gcc -index 357b0bed0..a88cface2 100644 ---- a/gcc/config.gcc -+++ b/gcc/config.gcc -@@ -822,6 +822,15 @@ case ${target} in - tmake_file="${tmake_file} t-freebsd" - target_has_targetdm=yes - ;; -+*-*-aero*) -+ extra_options="$extra_options gnu-user.opt" -+ gas=yes -+ gnu_ld=yes -+ default_use_cxa_atexit=yes -+ use_gcc_stdint=wrap -+ tmake_file="${tmake_file} t-slibgcc" -+ thread_file='posix' -+ ;; - *-*-fuchsia*) - native_system_header_dir=/include - ;; -@@ -2240,6 +2249,9 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) - ;; - esac - ;; -+x86_64-*-aero*) -+ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h gnu-user.h glibc-stdint.h i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h aero.h" -+ ;; - x86_64-*-fuchsia*) - tmake_file="${tmake_file} i386/t-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 fuchsia.h" -diff --git a/gcc/config/aero.h b/gcc/config/aero.h -new file mode 100644 -index 000000000..e8c149e40 ---- /dev/null -+++ b/gcc/config/aero.h -@@ -0,0 +1,30 @@ -+#undef TARGET_AERO -+#define TARGET_AERO 1 -+ -+#undef LIB_SPEC -+#define LIB_SPEC "-lc -lm" -+ -+#undef STARTFILE_SPEC -+#define STARTFILE_SPEC "%{!shared:crt0.o%s} crti.o%s %{shared:crtbeginS.o%s;:crtbegin.o%s}" -+ -+#undef ENDFILE_SPEC -+#define ENDFILE_SPEC "%{shared:crtendS.o%s;:crtend.o%s} crtn.o%s" -+ -+#define GNU_USER_LINK_EMULATION32 "elf_i386" -+#define GNU_USER_LINK_EMULATION64 "elf_x86_64" -+#define GNU_USER_LINK_EMULATIONX32 "elf32_x86_64" -+ -+#define GNU_USER_DYNAMIC_LINKER32 "/usr/lib/ld_i386.so" -+#define GNU_USER_DYNAMIC_LINKER64 "/usr/lib/ld.so" -+#define GNU_USER_DYNAMIC_LINKERX32 "/usr/lib/ld32.so" -+ -+#undef TARGET_OS_CPP_BUILTINS -+#define TARGET_OS_CPP_BUILTINS() \ -+ do \ -+ { \ -+ builtin_define("__aero__"); \ -+ builtin_define("__unix__"); \ -+ builtin_assert("system=aero"); \ -+ builtin_assert("system=unix"); \ -+ builtin_assert("system=posix"); \ -+ } while (0); -diff --git a/libgcc/config.host b/libgcc/config.host -index 50f000622..d1aa00f1a 100644 ---- a/libgcc/config.host -+++ b/libgcc/config.host -@@ -245,6 +245,11 @@ case ${host} in - tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-fuchsia" - extra_parts="crtbegin.o crtend.o" - ;; -+*-*-aero*) -+ extra_parts="$extra_parts crti.o crtbegin.o crtbeginS.o crtend.o crtendS.o crtn.o" -+ tmake_file="$tmake_file t-crtstuff-pic" -+ tmake_file="$tmake_file t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-libgcc-pic" -+ ;; - *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu | *-*-uclinuxfdpiceabi) - tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux" - extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" -@@ -703,6 +708,9 @@ x86_64-*-elf* | x86_64-*-rtems*) - x86_64-*-fuchsia*) - tmake_file="$tmake_file t-libgcc-pic" - ;; -+x86_64-*-aero*) -+ tmake_file="$tmake_file i386/t-crtstuff" -+ ;; - i[34567]86-*-dragonfly*) - tmake_file="${tmake_file} i386/t-dragonfly i386/t-crtstuff" - md_unwind_header=i386/dragonfly-unwind.h -diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h -index 7b0d367ec..2bce0a7e1 100644 ---- a/libgcc/libgcov.h -+++ b/libgcc/libgcov.h -@@ -44,6 +44,7 @@ - #include "tm.h" - #include "libgcc_tm.h" - #include "gcov.h" -+#include - - #if HAVE_SYS_MMAN_H - #include -diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4 -index ff44d5ae0..8b41eb058 100644 ---- a/libstdc++-v3/crossconfig.m4 -+++ b/libstdc++-v3/crossconfig.m4 -@@ -136,6 +136,18 @@ case "${host}" in - AC_CHECK_FUNCS(uselocale) - ;; - -+ *-aero*) -+ GLIBCXX_CHECK_COMPILER_FEATURES -+ GLIBCXX_CHECK_LINKER_FEATURES -+ GLIBCXX_CHECK_MATH_SUPPORT -+ GLIBCXX_CHECK_STDLIB_SUPPORT -+ AC_DEFINE(_GLIBCXX_USE_DEV_RANDOM) -+ AC_DEFINE(_GLIBCXX_USE_RANDOM_TR1) -+ GCC_CHECK_TLS -+ AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) -+ AC_CHECK_FUNCS(timespec_get) -+ ;; -+ - *-fuchsia*) - SECTION_FLAGS='-ffunction-sections -fdata-sections' - AC_SUBST(SECTION_FLAGS) -diff --git a/libtool.m4 b/libtool.m4 -index 17f8e5f30..5d29258d9 100644 ---- a/libtool.m4 -+++ b/libtool.m4 -@@ -2491,6 +2491,16 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu* | uclinuxfdpiceabi) - dynamic_linker='GNU/Linux ld.so' - ;; - -+aero*) -+ version_type=linux -+ need_lib_prefix=no -+ need_version=no -+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' -+ soname_spec='${libname}${release}${shared_ext}$major' -+ shlibpath_var=LD_LIBRARY_PATH -+ hardcode_into_libs=yes -+ ;; -+ - netbsd*) - version_type=sunos - need_lib_prefix=no -@@ -3090,6 +3100,10 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) - lt_cv_deplibs_check_method=pass_all - ;; - -+aero*) -+ lt_cv_deplibs_check_method=pass_all -+ ;; -+ - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' --- -2.25.1 - diff --git a/patches/glib/jinx-working-patch.patch b/patches/glib/jinx-working-patch.patch new file mode 100644 index 00000000000..5469c6c890a --- /dev/null +++ b/patches/glib/jinx-working-patch.patch @@ -0,0 +1,53 @@ +diff --git glib-clean/gio/gcredentialsprivate.h glib-workdir/gio/gcredentialsprivate.h +index 0310a75..f967f90 100644 +--- glib-clean/gio/gcredentialsprivate.h ++++ glib-workdir/gio/gcredentialsprivate.h +@@ -104,7 +104,7 @@ + */ + #undef G_CREDENTIALS_HAS_PID + +-#ifdef __linux__ ++#if defined(__linux__) || defined(__aero__) + #define G_CREDENTIALS_SUPPORTED 1 + #define G_CREDENTIALS_USE_LINUX_UCRED 1 + #define G_CREDENTIALS_NATIVE_TYPE G_CREDENTIALS_TYPE_LINUX_UCRED +diff --git glib-clean/glib/giounix.c glib-workdir/glib/giounix.c +index 84e8135..5b68f25 100644 +--- glib-clean/glib/giounix.c ++++ glib-workdir/glib/giounix.c +@@ -440,7 +440,10 @@ g_io_unix_get_flags (GIOChannel *channel) + channel->is_writeable = TRUE; + break; + default: +- g_assert_not_reached (); ++ channel->is_readable = TRUE; ++ channel->is_writeable = TRUE; ++ break; ++ // g_assert_not_reached (); + } + + return flags; +diff --git glib-clean/glib/glib-init.c glib-workdir/glib/glib-init.c +index 933f891..393e51d 100644 +--- glib-clean/glib/glib-init.c ++++ glib-workdir/glib/glib-init.c +@@ -29,6 +29,7 @@ + #include "gmem.h" /* for g_mem_gc_friendly */ + + #include ++#include + #include + #include + #include +diff --git glib-clean/glib/gstrfuncs.c glib-workdir/glib/gstrfuncs.c +index 22a608d..29e123c 100644 +--- glib-clean/glib/gstrfuncs.c ++++ glib-workdir/glib/gstrfuncs.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/patches/gtk+-3/jinx-working-patch.patch b/patches/gtk+-3/jinx-working-patch.patch new file mode 100644 index 00000000000..3dfbaf5c570 --- /dev/null +++ b/patches/gtk+-3/jinx-working-patch.patch @@ -0,0 +1,37 @@ +diff --git gtk+-3-clean/gtk/a11y/gtkaccessibility.c gtk+-3-workdir/gtk/a11y/gtkaccessibility.c +index 7f0e520..3bf670c 100644 +--- gtk+-3-clean/gtk/a11y/gtkaccessibility.c ++++ gtk+-3-workdir/gtk/a11y/gtkaccessibility.c +@@ -974,6 +974,10 @@ do_window_event_initialization (void) + void + _gtk_accessibility_init (void) + { ++// We don't care about a11y at this point in time and dbus isn't working, so let's just not start that. ++#ifdef __aero__ ++ return; ++#else + if (initialized) + return; + +@@ -993,4 +997,5 @@ _gtk_accessibility_init (void) + #endif + + atk_misc_instance = g_object_new (GTK_TYPE_MISC_IMPL, NULL); ++#endif + } +diff --git gtk+-3-clean/gtk/gtkmain.c gtk+-3-workdir/gtk/gtkmain.c +index ae64e18..2d43754 100644 +--- gtk+-3-clean/gtk/gtkmain.c ++++ gtk+-3-workdir/gtk/gtkmain.c +@@ -355,6 +355,11 @@ static gboolean + check_setugid (void) + { + /* this isn't at all relevant on MS Windows and doesn't compile ... --hb */ ++#ifdef __aero__ ++ /* Lyre runs everything as root for the time being, this check is thus useless. */ ++ g_warning("Lyre ignores the setugid check!\n"); ++ return TRUE; ++#endif + #ifndef G_OS_WIN32 + uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ + gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ diff --git a/patches/libdrm/libdrm.patch b/patches/libdrm/libdrm.patch deleted file mode 100644 index ff811a0bccd..00000000000 --- a/patches/libdrm/libdrm.patch +++ /dev/null @@ -1,147 +0,0 @@ -From c1dbfc87b74825c0f21b9031fc932d27908fcc71 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Sat, 14 May 2022 14:42:38 +1000 -Subject: [PATCH] drm: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 1 + - include/drm/drm.h | 4 ++-- - xf86drm.c | 20 ++++++++++---------- - xf86drm.h | 2 +- - 4 files changed, 14 insertions(+), 13 deletions(-) - -diff --git a/.gitignore b/.gitignore -index 0ec9e7f..e0c197e 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -1 +1,2 @@ - /build* -+.vscode -diff --git a/include/drm/drm.h b/include/drm/drm.h -index 398c396..3e35299 100644 ---- a/include/drm/drm.h -+++ b/include/drm/drm.h -@@ -35,10 +35,10 @@ - #ifndef _DRM_H_ - #define _DRM_H_ - --#if defined(__linux__) -+#if defined(__linux__) || defined(__aero__) - -+#include - #include --#include - typedef unsigned int drm_handle_t; - - #else /* One of the BSDs */ -diff --git a/xf86drm.c b/xf86drm.c -index 5933e4b..2b79641 100644 ---- a/xf86drm.c -+++ b/xf86drm.c -@@ -3346,7 +3346,7 @@ drm_public int drmCloseBufferHandle(int fd, uint32_t handle) - - static char *drmGetMinorNameForFD(int fd, int type) - { --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - DIR *sysdir; - struct dirent *ent; - struct stat sbuf; -@@ -3468,7 +3468,7 @@ drm_public char *drmGetRenderDeviceNameFromFd(int fd) - return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); - } - --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - static char * DRM_PRINTFLIKE(2, 3) - sysfs_uevent_get(const char *path, const char *fmt, ...) - { -@@ -3515,7 +3515,7 @@ sysfs_uevent_get(const char *path, const char *fmt, ...) - /* Little white lie to avoid major rework of the existing code */ - #define DRM_BUS_VIRTIO 0x10 - --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - static int get_subsystem_type(const char *device_path) - { - char path[PATH_MAX + 1] = ""; -@@ -3581,7 +3581,7 @@ static int drmParseSubsystemType(int maj, int min) - #endif - } - --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - static void - get_pci_path(int maj, int min, char *pci_path) - { -@@ -3661,7 +3661,7 @@ static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) - - static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) - { --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - unsigned int domain, bus, dev, func; - char pci_path[PATH_MAX + 1], *value; - int num; -@@ -3770,7 +3770,7 @@ static int drmGetMaxNodeName(void) - 3 /* length of the node number */; - } - --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - static int parse_separate_sysfs_files(int maj, int min, - drmPciDeviceInfoPtr device, - bool ignore_revision) -@@ -3848,7 +3848,7 @@ static int drmParsePciDeviceInfo(int maj, int min, - drmPciDeviceInfoPtr device, - uint32_t flags) - { --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) - return parse_separate_sysfs_files(maj, min, device, true); - -@@ -4072,7 +4072,7 @@ free_device: - return ret; - } - --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - static int drm_usb_dev_path(int maj, int min, char *path, size_t len) - { - char *value, *tmp_path, *slash; -@@ -4160,7 +4160,7 @@ static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) - - static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) - { --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - char path[PATH_MAX + 1], *value; - unsigned int vendor, product; - int ret; -@@ -4760,7 +4760,7 @@ drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) - - drm_public char *drmGetDeviceNameFromFd2(int fd) - { --#ifdef __linux__ -+#if defined(__linux__) || defined(__aero__) - struct stat sbuf; - char path[PATH_MAX + 1], *value; - unsigned int maj, min; -diff --git a/xf86drm.h b/xf86drm.h -index 1631396..a2118f1 100644 ---- a/xf86drm.h -+++ b/xf86drm.h -@@ -47,7 +47,7 @@ extern "C" { - #define DRM_MAX_MINOR 16 - #endif - --#if defined(__linux__) -+#if defined(__linux__) || defined(__aero__) - - #define DRM_IOCTL_NR(n) _IOC_NR(n) - #define DRM_IOC_VOID _IOC_NONE --- -2.25.1 - diff --git a/patches/libgcrypt/jinx-working-patch.patch b/patches/libgcrypt/jinx-working-patch.patch new file mode 100644 index 00000000000..a86085ff566 --- /dev/null +++ b/patches/libgcrypt/jinx-working-patch.patch @@ -0,0 +1,23 @@ +diff --git a/random/rndunix.c b/random/rndunix.c +index fcb45b7..1e32242 100644 +--- a/random/rndunix.c ++++ b/random/rndunix.c +@@ -105,7 +105,7 @@ + #include + #include + #include +-#ifndef __QNX__ ++#if !defined __QNX__ && !defined (__aero__) + #include + #include + #endif /* __QNX__ */ +@@ -119,7 +119,9 @@ + #ifndef __QNX__ + #include + #include ++#ifndef __aero__ + #include ++#endif + #endif /* __QNX__ */ + #include + #include /* Verschiedene komische Typen */ diff --git a/patches/libiconv/0001-libiconv-aero-specific-changes.patch b/patches/libiconv/0001-libiconv-aero-specific-changes.patch deleted file mode 100644 index 6a7e24eaaf2..00000000000 --- a/patches/libiconv/0001-libiconv-aero-specific-changes.patch +++ /dev/null @@ -1,50 +0,0 @@ -From d29c791b1dfcd9459e7f9ee1101a035ee31daa75 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Wed, 29 Jun 2022 18:57:29 +1000 -Subject: [PATCH] libiconv: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - Makefile.devel | 8 ++++---- - libcharset/Makefile.devel | 6 +++--- - 2 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/Makefile.devel b/Makefile.devel -index 2a5e101..a179aaf 100644 ---- a/Makefile.devel -+++ b/Makefile.devel -@@ -4,10 +4,10 @@ - - SHELL = /bin/sh - MAKE = make --AUTOCONF = autoconf-2.69 --AUTOHEADER = autoheader-2.69 --AUTOMAKE = automake-1.16 --ACLOCAL = aclocal-1.16 -+AUTOCONF = autoconf -+AUTOHEADER = autoheader -+AUTOMAKE = automake -+ACLOCAL = aclocal - GPERF = gperf - CC = gcc -Wall - CFLAGS = -O -diff --git a/libcharset/Makefile.devel b/libcharset/Makefile.devel -index 04f4c7a..3e0e2ca 100644 ---- a/libcharset/Makefile.devel -+++ b/libcharset/Makefile.devel -@@ -3,9 +3,9 @@ - - SHELL = /bin/sh - MAKE = make --AUTOCONF = autoconf-2.69 --AUTOHEADER = autoheader-2.69 --ACLOCAL = aclocal-1.16 -+AUTOCONF = autoconf -+AUTOHEADER = autoheader -+ACLOCAL = aclocal - CP = cp - RM = rm -f - --- -2.25.1 - diff --git a/patches/libtool/jinx-working-patch.patch b/patches/libtool/jinx-working-patch.patch new file mode 100644 index 00000000000..d2f5a84233a --- /dev/null +++ b/patches/libtool/jinx-working-patch.patch @@ -0,0 +1,138 @@ +diff --git libtool-clean/build-aux/ltmain.in libtool-workdir/build-aux/ltmain.in +index a5f21a1..c06d55c 100644 +--- libtool-clean/build-aux/ltmain.in ++++ libtool-workdir/build-aux/ltmain.in +@@ -6497,7 +6497,7 @@ func_mode_link () + fi + else + # We cannot seem to hardcode it, guess we'll fake it. +- add_dir=-L$libdir ++ add_dir=-L$lt_sysroot$libdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in +diff --git libtool-clean/libtoolize.in libtool-workdir/libtoolize.in +index 0c40fed..763619b 100644 +--- libtool-clean/libtoolize.in ++++ libtool-workdir/libtoolize.in +@@ -1891,7 +1891,7 @@ func_require_seen_libtool () + # Do not remove config.guess, config.sub or install-sh, we don't + # install them without --install, and the project may not be using + # Automake. Similarly, do not remove Gnulib files. +- all_pkgaux_files="compile depcomp missing ltmain.sh" ++ all_pkgaux_files="" + all_pkgmacro_files="libtool.m4 ltargz.m4 ltdl.m4 ltoptions.m4 ltsugar.m4 ltversion.in ltversion.m4 lt~obsolete.m4" + all_pkgltdl_files="COPYING.LIB Makefile Makefile.in Makefile.inc Makefile.am README acinclude.m4 aclocal.m4 argz_.h argz.c config.h.in config-h.in configure configure.ac configure.in libltdl/lt__alloc.h libltdl/lt__argz.h libltdl/lt__dirent.h libltdl/lt__glibc.h libltdl/lt__private.h libltdl/lt__strl.h libltdl/lt_dlloader.h libltdl/lt_error.h libltdl/lt_system.h libltdl/slist.h loaders/dld_link.c loaders/dlopen.c loaders/dyld.c loaders/load_add_on.c loaders/loadlibrary.c loaders/preopen.c loaders/shl_load.c lt__alloc.c lt__argz.c lt__dirent.c lt__strl.c lt_dlloader.c lt_error.c ltdl.c ltdl.h ltdl.mk slist.c" + +diff --git libtool-clean/m4/libtool.m4 libtool-workdir/m4/libtool.m4 +index 79a2451..b6e8ca4 100644 +--- libtool-clean/m4/libtool.m4 ++++ libtool-workdir/m4/libtool.m4 +@@ -1696,7 +1696,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + +- gnu*) ++ gnu* | aero*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever +@@ -2925,6 +2925,18 @@ netbsd*) + hardcode_into_libs=yes + ;; + ++aero*) ++ version_type=linux # correct to gnu/linux during the next big refactor ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ++ soname_spec='$libname$release$shared_ext$major' ++ dynamic_linker='mlibc ld.so' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ + newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' +@@ -3566,6 +3578,10 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + ++aero*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' +@@ -4446,6 +4462,8 @@ m4_if([$1], [CXX], [ + ;; + netbsd*) + ;; ++ aero*) ++ ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. +@@ -4794,6 +4812,12 @@ m4_if([$1], [CXX], [ + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ++ aero*) ++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ++ ;; ++ + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. +@@ -5273,6 +5297,11 @@ _LT_EOF + fi + ;; + ++ aero*) ++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' ++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ++ ;; ++ + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' +@@ -5815,6 +5844,9 @@ _LT_EOF + esac + ;; + ++ aero*) ++ ;; ++ + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out +@@ -7115,6 +7147,10 @@ if test yes != "$_lt_caught_CXX_error"; then + esac + ;; + ++ aero*) ++ _LT_TAGVAR(ld_shlibs, $1)=yes ++ ;; ++ + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' +diff --git libtool-clean/m4/ltdl.m4 libtool-workdir/m4/ltdl.m4 +index 772c150..642966e 100644 +--- libtool-clean/m4/ltdl.m4 ++++ libtool-workdir/m4/ltdl.m4 +@@ -497,6 +497,9 @@ AC_CACHE_CHECK([whether deplibs are loaded by dlopen], + # at 6.2 and later dlopen does load deplibs. + lt_cv_sys_dlopen_deplibs=yes + ;; ++ aero*) ++ lt_cv_sys_dlopen_deplibs=yes ++ ;; + netbsd*) + lt_cv_sys_dlopen_deplibs=yes + ;; diff --git a/patches/libtool/libtool.patch b/patches/libtool/libtool.patch deleted file mode 100644 index ae10581cfd1..00000000000 --- a/patches/libtool/libtool.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 634f15ee7db8317cb39e1f13dbd1e4cd16f922e6 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Wed, 25 May 2022 16:43:44 +1000 -Subject: [PATCH] libtool: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - build-aux/ltmain.in | 2 +- - m4/libtool.m4 | 15 +++++++++++++++ - 2 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/build-aux/ltmain.in b/build-aux/ltmain.in -index d5cf07a..ce97a5f 100644 ---- a/build-aux/ltmain.in -+++ b/build-aux/ltmain.in -@@ -6449,7 +6449,7 @@ func_mode_link () - fi - else - # We cannot seem to hardcode it, guess we'll fake it. -- add_dir=-L$libdir -+ add_dir=-L$lt_sysroot$libdir - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in -diff --git a/m4/libtool.m4 b/m4/libtool.m4 -index a3bc337..9136171 100644 ---- a/m4/libtool.m4 -+++ b/m4/libtool.m4 -@@ -2905,6 +2905,17 @@ netbsd*) - hardcode_into_libs=yes - ;; - -+aero*) -+ version_type=linux # correct to gnu/linux during the next big refactor -+ need_lib_prefix=no -+ need_version=no -+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' -+ soname_spec='$libname$release$shared_ext$major' -+ shlibpath_var=LD_LIBRARY_PATH -+ shlibpath_overrides_runpath=no -+ hardcode_into_libs=yes -+ ;; -+ - newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' -@@ -3554,6 +3565,10 @@ netbsd*) - fi - ;; - -+aero*) -+ lt_cv_deplibs_check_method=pass_all -+ ;; -+ - newos6*) - lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file --- -2.25.1 - diff --git a/patches/libxfont2/0001-libxfont2-aero-specific-changes.patch b/patches/libxfont2/0001-libxfont2-aero-specific-changes.patch deleted file mode 100644 index e4453bba46f..00000000000 --- a/patches/libxfont2/0001-libxfont2-aero-specific-changes.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0da59aec1e86152858f47e12da033883e4b16852 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Thu, 30 Jun 2022 10:46:56 +1000 -Subject: [PATCH] libxfont2: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 2 ++ - src/fc/fslibos.h | 2 +- - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/.gitignore b/.gitignore -index 2efa153..4370b7e 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -79,3 +79,5 @@ core - *.sig - *.announce - TAGS -+# editor configs: -+.vscode -diff --git a/src/fc/fslibos.h b/src/fc/fslibos.h -index 1ef362d..a9935d1 100644 ---- a/src/fc/fslibos.h -+++ b/src/fc/fslibos.h -@@ -60,7 +60,7 @@ from The Open Group. - # endif - # endif - # ifndef OPEN_MAX --# if defined(SVR4) -+# if defined(SVR4) || defined(__aero__) - # define OPEN_MAX 256 - # else - # include --- -2.25.1 - diff --git a/patches/llvm/llvm.patch b/patches/llvm/jinx-working-patch.patch similarity index 66% rename from patches/llvm/llvm.patch rename to patches/llvm/jinx-working-patch.patch index fdf2018b488..2ac261e9954 100644 --- a/patches/llvm/llvm.patch +++ b/patches/llvm/jinx-working-patch.patch @@ -1,68 +1,11 @@ -From e8b0511dc10a7bf17b34021e58f7ca71bef59fc5 Mon Sep 17 00:00:00 2001 -From: czapek1337 -Date: Sat, 8 Jan 2022 05:22:31 +0100 -Subject: [PATCH] targets: add new aero target - ---- - clang/lib/Basic/Targets.cpp | 6 + - clang/lib/Basic/Targets/OSTargets.h | 28 ++ - clang/lib/Driver/CMakeLists.txt | 1 + - clang/lib/Driver/Driver.cpp | 4 + - clang/lib/Driver/ToolChains/Aero.cpp | 438 ++++++++++++++++++ - clang/lib/Driver/ToolChains/Aero.h | 49 ++ - clang/lib/Driver/ToolChains/Gnu.cpp | 13 +- - llvm/cmake/modules/CrossCompile.cmake | 4 +- - llvm/include/llvm/ADT/Triple.h | 5 +- - llvm/include/llvm/Support/SwapByteOrder.h | 2 +- - llvm/lib/Support/Triple.cpp | 6 + - llvm/lib/Support/Unix/Path.inc | 6 +- - llvm/lib/Support/Unix/Program.inc | 1 + - llvm/tools/llvm-dwarfdump/Statistics.cpp | 1 + - llvm/tools/llvm-shlib/CMakeLists.txt | 1 + - llvm/utils/benchmark/src/benchmark_register.h | 1 + - 16 files changed, 556 insertions(+), 10 deletions(-) - create mode 100644 clang/lib/Driver/ToolChains/Aero.cpp - create mode 100644 clang/lib/Driver/ToolChains/Aero.h - -diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp -index c063f8ca4..d8b6878f1 100644 ---- a/clang/lib/Basic/Targets.cpp -+++ b/clang/lib/Basic/Targets.cpp -@@ -144,6 +144,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, - return new NetBSDTargetInfo(Triple, Opts); - case llvm::Triple::OpenBSD: - return new OpenBSDTargetInfo(Triple, Opts); -+ case llvm::Triple::Aero: -+ return new AeroTargetInfo(Triple, Opts); - case llvm::Triple::Win32: - switch (Triple.getEnvironment()) { - case llvm::Triple::GNU: -@@ -387,6 +389,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, - return new FuchsiaTargetInfo(Triple, Opts); - case llvm::Triple::Linux: - return new LinuxTargetInfo(Triple, Opts); -+ case llvm::Triple::Aero: -+ return new AeroTargetInfo(Triple, Opts); - default: - return new RISCV64TargetInfo(Triple, Opts); - } -@@ -553,6 +557,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, - } - case llvm::Triple::Haiku: - return new HaikuTargetInfo(Triple, Opts); -+ case llvm::Triple::Aero: -+ return new AeroTargetInfo(Triple, Opts); - case llvm::Triple::NaCl: - return new NaClTargetInfo(Triple, Opts); - case llvm::Triple::PS4: -diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h -index 70fac030b..93fc21c3d 100644 ---- a/clang/lib/Basic/Targets/OSTargets.h -+++ b/clang/lib/Basic/Targets/OSTargets.h -@@ -342,6 +342,34 @@ public: - : OSTargetInfo(Triple, Opts) {} +diff --git llvm-clean/clang/lib/Basic/Targets/OSTargets.h llvm-workdir/clang/lib/Basic/Targets/OSTargets.h +index cf8cc8e..19984dc 100644 +--- llvm-clean/clang/lib/Basic/Targets/OSTargets.h ++++ llvm-workdir/clang/lib/Basic/Targets/OSTargets.h +@@ -922,6 +922,34 @@ public: + } }; - + +// Aero Target +template +class LLVM_LIBRARY_VISIBILITY AeroTargetInfo : public OSTargetInfo { @@ -91,34 +34,47 @@ index 70fac030b..93fc21c3d 100644 + } +}; + - // Minix Target + // WebAssembly target template - class LLVM_LIBRARY_VISIBILITY MinixTargetInfo : public OSTargetInfo { -diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt -index 6f25d3588..a59e549ef 100644 ---- a/clang/lib/Driver/CMakeLists.txt -+++ b/clang/lib/Driver/CMakeLists.txt -@@ -54,6 +54,7 @@ add_clang_library(clangDriver - ToolChains/Hexagon.cpp - ToolChains/Hurd.cpp - ToolChains/Linux.cpp + class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo +diff --git llvm-clean/clang/lib/Basic/Targets.cpp llvm-workdir/clang/lib/Basic/Targets.cpp +index 636b59f..98ef355 100644 +--- llvm-clean/clang/lib/Basic/Targets.cpp ++++ llvm-workdir/clang/lib/Basic/Targets.cpp +@@ -590,6 +590,8 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, + } + case llvm::Triple::Haiku: + return std::make_unique(Triple, Opts); ++ case llvm::Triple::Aero: ++ return std::make_unique>(Triple, Opts); + case llvm::Triple::RTEMS: + return std::make_unique(Triple, Opts); + case llvm::Triple::NaCl: +diff --git llvm-clean/clang/lib/Driver/CMakeLists.txt llvm-workdir/clang/lib/Driver/CMakeLists.txt +index a6bd2d4..81893cf 100644 +--- llvm-clean/clang/lib/Driver/CMakeLists.txt ++++ llvm-workdir/clang/lib/Driver/CMakeLists.txt +@@ -76,6 +76,7 @@ add_clang_library(clangDriver + ToolChains/Myriad.cpp + ToolChains/NaCl.cpp + ToolChains/NetBSD.cpp + ToolChains/Aero.cpp - ToolChains/MipsLinux.cpp - ToolChains/MinGW.cpp - ToolChains/Minix.cpp -diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp -index fb8335a36..05adcae7d 100644 ---- a/clang/lib/Driver/Driver.cpp -+++ b/clang/lib/Driver/Driver.cpp -@@ -29,6 +29,7 @@ - #include "ToolChains/Hurd.h" - #include "ToolChains/Lanai.h" - #include "ToolChains/Linux.h" + ToolChains/OHOS.cpp + ToolChains/OpenBSD.cpp + ToolChains/PS4CPU.cpp +diff --git llvm-clean/clang/lib/Driver/Driver.cpp llvm-workdir/clang/lib/Driver/Driver.cpp +index bdbdad9..1dd717e 100644 +--- llvm-clean/clang/lib/Driver/Driver.cpp ++++ llvm-workdir/clang/lib/Driver/Driver.cpp +@@ -20,6 +20,7 @@ + #include "ToolChains/Contiki.h" + #include "ToolChains/CrossWindows.h" + #include "ToolChains/Cuda.h" +#include "ToolChains/Aero.h" - #include "ToolChains/MSP430.h" - #include "ToolChains/MSVC.h" - #include "ToolChains/MinGW.h" -@@ -4853,6 +4854,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, + #include "ToolChains/Darwin.h" + #include "ToolChains/DragonFly.h" + #include "ToolChains/FreeBSD.h" +@@ -6225,6 +6226,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Fuchsia: TC = std::make_unique(*this, Target, Args); break; @@ -128,12 +84,12 @@ index fb8335a36..05adcae7d 100644 case llvm::Triple::Solaris: TC = std::make_unique(*this, Target, Args); break; -diff --git a/clang/lib/Driver/ToolChains/Aero.cpp b/clang/lib/Driver/ToolChains/Aero.cpp +diff --git llvm-workdir/clang/lib/Driver/ToolChains/Aero.cpp llvm-workdir/clang/lib/Driver/ToolChains/Aero.cpp new file mode 100644 -index 000000000..4cd7765ae +index 0000000..580d85c --- /dev/null -+++ b/clang/lib/Driver/ToolChains/Aero.cpp -@@ -0,0 +1,438 @@ ++++ llvm-workdir/clang/lib/Driver/ToolChains/Aero.cpp +@@ -0,0 +1,432 @@ +//===--- Aero.h - Aero ToolChain Implementations --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure @@ -247,13 +203,13 @@ index 000000000..4cd7765ae + // to the link paths. + path_list &Paths = getFilePaths(); + -+ const std::string OSLibDir = getOSLibDir(Triple, Args); ++ const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); + const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + + // Add the multilib suffixed paths where they are available. + if (GCCInstallation.isValid()) { + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); -+ const std::string &LibPath = GCCInstallation.getParentLibPath(); ++ const std::string &LibPath = std::string(GCCInstallation.getParentLibPath()); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const MultilibSet &Multilibs = GCCInstallation.getMultilibs(); + @@ -336,7 +292,7 @@ index 000000000..4cd7765ae + + // See comments above on the multilib variant for details of why this is + // included even from outside the sysroot. -+ const std::string &LibPath = GCCInstallation.getParentLibPath(); ++ const std::string &LibPath = std::string(GCCInstallation.getParentLibPath()); + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + @@ -495,11 +451,9 @@ index 000000000..4cd7765ae + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); + const GCCVersion &Version = GCCInstallation.getVersion(); + -+ // The primary search for libstdc++ supports multiarch variants. -+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", -+ "/c++/" + Version.Text, TripleStr, -+ GCCMultiarchTriple, TargetMultiarchTriple, -+ Multilib.includeSuffix(), DriverArgs, CC1Args)) ++ // Try generic GCC detection first. ++ if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, ++ TripleStr)) + return; + + // Otherwise, fall back on a bunch of options which don't use multiarch @@ -519,10 +473,7 @@ index 000000000..4cd7765ae + }; + + for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { -+ if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, -+ /*GCCMultiarchTriple*/ "", -+ /*TargetMultiarchTriple*/ "", -+ Multilib.includeSuffix(), DriverArgs, CC1Args)) ++ if (addLibStdCXXIncludePaths(IncludePath, TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args)) + break; + } +} @@ -571,12 +522,11 @@ index 000000000..4cd7765ae + Res |= SanitizerKind::MemTag; + return Res; +} -+ -diff --git a/clang/lib/Driver/ToolChains/Aero.h b/clang/lib/Driver/ToolChains/Aero.h +diff --git llvm-workdir/clang/lib/Driver/ToolChains/Aero.h llvm-workdir/clang/lib/Driver/ToolChains/Aero.h new file mode 100644 -index 000000000..e9016f4a8 +index 0000000..a7b0b4d --- /dev/null -+++ b/clang/lib/Driver/ToolChains/Aero.h ++++ llvm-workdir/clang/lib/Driver/ToolChains/Aero.h @@ -0,0 +1,49 @@ +//===--- Aero.h - Aero ToolChain Implementations --------*- C++ -*-===// +// @@ -587,8 +537,8 @@ index 000000000..e9016f4a8 +// +//===----------------------------------------------------------------------===// + -+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MANAGARM_H -+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MANAGARM_H ++#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AERO_H ++#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AERO_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" @@ -611,9 +561,9 @@ index 000000000..e9016f4a8 + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + SanitizerMask getSupportedSanitizers() const override; -+ virtual std::string computeSysRoot() const; + -+ virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; ++ virtual std::string computeSysRoot() const override; ++ virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const override; + + std::vector ExtraOpts; + @@ -626,59 +576,27 @@ index 000000000..e9016f4a8 +} // end namespace driver +} // end namespace clang + -+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MANAGARM_H -diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp -index da39f29e4..b6f6bb439 100644 ---- a/clang/lib/Driver/ToolChains/Gnu.cpp -+++ b/clang/lib/Driver/ToolChains/Gnu.cpp -@@ -246,6 +246,8 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { - return "elf_iamcu"; - return "elf_i386"; - case llvm::Triple::aarch64: -+ if (T.getOS() == llvm::Triple::Aero) -+ return "aarch64aero"; - return "aarch64linux"; - case llvm::Triple::aarch64_be: - return "aarch64linuxb"; -@@ -2077,7 +2079,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( - static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; - static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", -- "aarch64-suse-linux", "aarch64-linux-android"}; -+ "aarch64-suse-linux", "aarch64-linux-android", -+ "aarch64-aero", "aarch64-aero-system", "aarch64-aero-kernel"}; - static const char *const AArch64beLibDirs[] = {"/lib"}; - static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", - "aarch64_be-linux-gnu"}; -@@ -2105,7 +2108,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( ++#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AERO_H +diff --git llvm-clean/clang/lib/Driver/ToolChains/Gnu.cpp llvm-workdir/clang/lib/Driver/ToolChains/Gnu.cpp +index 40038dc..86a5c53 100644 +--- llvm-clean/clang/lib/Driver/ToolChains/Gnu.cpp ++++ llvm-workdir/clang/lib/Driver/ToolChains/Gnu.cpp +@@ -2328,7 +2328,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", "x86_64-unknown-linux", -- "x86_64-amazon-linux", "x86_64-linux-android"}; -+ "x86_64-amazon-linux", "x86_64-linux-android", -+ "x86_64-aero", "x86_64-aero-system", "x86_64-aero-kernel"}; +- "x86_64-amazon-linux"}; ++ "x86_64-amazon-linux", "x86_64-aero"}; static const char *const X32Triples[] = {"x86_64-linux-gnux32", "x86_64-pc-linux-gnux32"}; static const char *const X32LibDirs[] = {"/libx32", "/lib"}; -@@ -2183,7 +2187,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( - "riscv64-linux-gnu", - "riscv64-unknown-elf", - "riscv64-redhat-linux", -- "riscv64-suse-linux"}; -+ "riscv64-suse-linux", -+ "riscv64-aero", -+ "riscv64-aero-kernel", -+ "riscv64-aero-system"}; - - static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; - static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", -diff --git a/llvm/cmake/modules/CrossCompile.cmake b/llvm/cmake/modules/CrossCompile.cmake -index 8a6e880c4..fb86a7c17 100644 ---- a/llvm/cmake/modules/CrossCompile.cmake -+++ b/llvm/cmake/modules/CrossCompile.cmake +diff --git llvm-clean/llvm/cmake/modules/CrossCompile.cmake llvm-workdir/llvm/cmake/modules/CrossCompile.cmake +index 6af47b5..78983fa 100644 +--- llvm-clean/llvm/cmake/modules/CrossCompile.cmake ++++ llvm-workdir/llvm/cmake/modules/CrossCompile.cmake @@ -17,8 +17,8 @@ function(llvm_create_cross_target project_name target_name toolchain buildtype) -DCMAKE_TOOLCHAIN_FILE=\"${LLVM_MAIN_SRC_DIR}/cmake/platforms/${toolchain}.cmake\") - else() + elseif (NOT CMAKE_CROSSCOMPILING) set(CROSS_TOOLCHAIN_FLAGS_INIT - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} @@ -687,104 +605,46 @@ index 8a6e880c4..fb86a7c17 100644 ) endif() set(CROSS_TOOLCHAIN_FLAGS_${target_name} ${CROSS_TOOLCHAIN_FLAGS_INIT} -diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h -index 76a754d67..5899b5449 100644 ---- a/llvm/include/llvm/ADT/Triple.h -+++ b/llvm/include/llvm/ADT/Triple.h -@@ -168,6 +168,7 @@ public: - Linux, - Lv2, // PS3 - MacOSX, -+ Aero, - NetBSD, - OpenBSD, - Solaris, -@@ -217,7 +218,9 @@ public: - CoreCLR, - Simulator, // Simulator variants of other systems, e.g., Apple's iOS - MacABI, // Mac Catalyst variant of Apple's iOS deployment target. -- LastEnvironmentType = MacABI -+ Kernel, -+ System, -+ LastEnvironmentType = System - }; - enum ObjectFormatType { - UnknownObjectFormat, -diff --git a/llvm/include/llvm/Support/SwapByteOrder.h b/llvm/include/llvm/Support/SwapByteOrder.h -index e8612ba66..7c4e941bd 100644 ---- a/llvm/include/llvm/Support/SwapByteOrder.h -+++ b/llvm/include/llvm/Support/SwapByteOrder.h -@@ -22,7 +22,7 @@ - #endif - +diff --git llvm-clean/llvm/include/llvm/Support/SwapByteOrder.h llvm-workdir/llvm/include/llvm/Support/SwapByteOrder.h +index 1bbc2e2..4b41da7 100644 +--- llvm-clean/llvm/include/llvm/Support/SwapByteOrder.h ++++ llvm-workdir/llvm/include/llvm/Support/SwapByteOrder.h +@@ -20,7 +20,7 @@ + #include + #if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \ - defined(__Fuchsia__) || defined(__EMSCRIPTEN__) + defined(__Fuchsia__) || defined(__EMSCRIPTEN__) || defined(__aero__) #include #elif defined(_AIX) #include -diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp -index 883115463..e27e27ecc 100644 ---- a/llvm/lib/Support/Triple.cpp -+++ b/llvm/lib/Support/Triple.cpp -@@ -189,6 +189,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { - case UnknownOS: return "unknown"; - - case AIX: return "aix"; -+ case Aero: return "aero"; - case AMDHSA: return "amdhsa"; - case AMDPAL: return "amdpal"; - case Ananas: return "ananas"; -@@ -245,6 +246,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { - case GNUX32: return "gnux32"; - case GNUILP32: return "gnu_ilp32"; - case Itanium: return "itanium"; -+ case Kernel: return "kernel"; - case MSVC: return "msvc"; - case MacABI: return "macabi"; - case Musl: return "musl"; -@@ -252,6 +254,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { - case MuslEABIHF: return "musleabihf"; - case MuslX32: return "muslx32"; - case Simulator: return "simulator"; -+ case System: return "system"; - } - - llvm_unreachable("Invalid EnvironmentType!"); -@@ -502,6 +505,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { - - static Triple::OSType parseOS(StringRef OSName) { - return StringSwitch(OSName) -+ .StartsWith("aero", Triple::Aero) - .StartsWith("ananas", Triple::Ananas) - .StartsWith("cloudabi", Triple::CloudABI) - .StartsWith("darwin", Triple::Darwin) -@@ -560,9 +564,11 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { - .StartsWith("musl", Triple::Musl) - .StartsWith("msvc", Triple::MSVC) - .StartsWith("itanium", Triple::Itanium) -+ .StartsWith("kernel", Triple::Kernel) - .StartsWith("cygnus", Triple::Cygnus) - .StartsWith("coreclr", Triple::CoreCLR) - .StartsWith("simulator", Triple::Simulator) -+ .StartsWith("system", Triple::System) - .StartsWith("macabi", Triple::MacABI) - .Default(Triple::UnknownEnvironment); - } -diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc -index 2a03dc682..e75ff461d 100644 ---- a/llvm/lib/Support/Unix/Path.inc -+++ b/llvm/lib/Support/Unix/Path.inc -@@ -64,7 +64,7 @@ extern char **environ; - +diff --git llvm-clean/llvm/include/llvm/TargetParser/Triple.h llvm-workdir/llvm/include/llvm/TargetParser/Triple.h +index 79ccd64..ae3bfb0 100644 +--- llvm-clean/llvm/include/llvm/TargetParser/Triple.h ++++ llvm-workdir/llvm/include/llvm/TargetParser/Triple.h +@@ -197,6 +197,7 @@ public: + Lv2, // PS3 + MacOSX, + NetBSD, ++ Aero, + OpenBSD, + Solaris, + UEFI, +diff --git llvm-clean/llvm/lib/Support/Unix/Path.inc llvm-workdir/llvm/lib/Support/Unix/Path.inc +index e2aece4..54741ac 100644 +--- llvm-clean/llvm/lib/Support/Unix/Path.inc ++++ llvm-workdir/llvm/lib/Support/Unix/Path.inc +@@ -74,7 +74,8 @@ extern char **environ; + #include #if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \ - !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX) -+ !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX) && !defined(__aero__) ++ !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX) && \ ++ !defined(__aero__) #include #define STATVFS statvfs #define FSTATVFS fstatvfs -@@ -73,7 +73,7 @@ extern char **environ; +@@ -83,7 +84,7 @@ extern char **environ; #if defined(__OpenBSD__) || defined(__FreeBSD__) #include #include @@ -793,51 +653,75 @@ index 2a03dc682..e75ff461d 100644 #if defined(HAVE_LINUX_MAGIC_H) #include #else -@@ -431,7 +431,7 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { +@@ -129,7 +130,7 @@ const file_t kInvalidFile = -1; + #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) || \ + defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX) || \ +- defined(__GNU__) || (defined(__sun__) && defined(__svr4__)) ++ defined(__GNU__) || (defined(__sun__) && defined(__svr4__)) || defined(__aero__) + static int test_dir(char ret[PATH_MAX], const char *dir, const char *bin) { + struct stat sb; + char fullpath[PATH_MAX]; +@@ -250,7 +251,8 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { + // If we don't have procfs mounted, fall back to argv[0] + if (getprogpath(exe_path, argv0) != NULL) + return exe_path; +-#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__) ++#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__) || \ ++ defined(__aero__) + char exe_path[PATH_MAX]; + const char *aPath = "/proc/self/exe"; + if (sys::fs::exists(aPath)) { +@@ -472,7 +474,7 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { } - + static bool is_local_impl(struct STATVFS &Vfs) { -#if defined(__linux__) || defined(__GNU__) +#if defined(__linux__) || defined(__GNU__) || defined(__aero__) #ifndef NFS_SUPER_MAGIC #define NFS_SUPER_MAGIC 0x6969 #endif -diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc -index 520685a0e..e6c2ddf20 100644 ---- a/llvm/lib/Support/Unix/Program.inc -+++ b/llvm/lib/Support/Unix/Program.inc -@@ -39,6 +39,7 @@ +diff --git llvm-clean/llvm/lib/Support/Unix/Program.inc llvm-workdir/llvm/lib/Support/Unix/Program.inc +index 897e227..02f74d7 100644 +--- llvm-clean/llvm/lib/Support/Unix/Program.inc ++++ llvm-workdir/llvm/lib/Support/Unix/Program.inc +@@ -41,6 +41,7 @@ #if HAVE_UNISTD_H #include #endif +#undef HAVE_POSIX_SPAWN #ifdef HAVE_POSIX_SPAWN #include - -diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp -index 19a971afa..929184bfc 100644 ---- a/llvm/tools/llvm-dwarfdump/Statistics.cpp -+++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp -@@ -6,6 +6,8 @@ - // - //===----------------------------------------------------------------------===// - -+#include -+ - #include "llvm-dwarfdump.h" - #include "llvm/ADT/DenseMap.h" - #include "llvm/ADT/StringSet.h" -diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt -index 3eb6db33a..554264a07 100644 ---- a/llvm/tools/llvm-shlib/CMakeLists.txt -+++ b/llvm/tools/llvm-shlib/CMakeLists.txt -@@ -36,6 +36,7 @@ if(LLVM_BUILD_LLVM_DYLIB) - if(("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") OR (MINGW) OR (HAIKU) - OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") - OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU") -+ OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "aero") + +diff --git llvm-clean/llvm/lib/TargetParser/Triple.cpp llvm-workdir/llvm/lib/TargetParser/Triple.cpp +index a3d6a06..f431d74 100644 +--- llvm-clean/llvm/lib/TargetParser/Triple.cpp ++++ llvm-workdir/llvm/lib/TargetParser/Triple.cpp +@@ -219,6 +219,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { + case Emscripten: return "emscripten"; + case FreeBSD: return "freebsd"; + case Fuchsia: return "fuchsia"; ++ case Aero: return "aero"; + case Haiku: return "haiku"; + case HermitCore: return "hermit"; + case Hurd: return "hurd"; +@@ -575,6 +576,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { + + static Triple::OSType parseOS(StringRef OSName) { + return StringSwitch(OSName) ++ .StartsWith("aero", Triple::Aero) + .StartsWith("ananas", Triple::Ananas) + .StartsWith("cloudabi", Triple::CloudABI) + .StartsWith("darwin", Triple::Darwin) +diff --git llvm-clean/llvm/tools/llvm-shlib/CMakeLists.txt llvm-workdir/llvm/tools/llvm-shlib/CMakeLists.txt +index 8ace190..b79c68d 100644 +--- llvm-clean/llvm/tools/llvm-shlib/CMakeLists.txt ++++ llvm-workdir/llvm/tools/llvm-shlib/CMakeLists.txt +@@ -41,6 +41,7 @@ if(LLVM_BUILD_LLVM_DYLIB) OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") - OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia") OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "DragonFly") --- -2.34.1 + OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia") ++ OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Aero") + OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") + OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")) # FIXME: It should be "GNU ld for elf" + configure_file( diff --git a/patches/mesa/jinx-working-patch.patch b/patches/mesa/jinx-working-patch.patch new file mode 100644 index 00000000000..20d43de4e12 --- /dev/null +++ b/patches/mesa/jinx-working-patch.patch @@ -0,0 +1,170 @@ +diff --git mesa-clean/include/drm-uapi/drm.h mesa-workdir/include/drm-uapi/drm.h +index 0254024..c2ffd35 100644 +--- mesa-clean/include/drm-uapi/drm.h ++++ mesa-workdir/include/drm-uapi/drm.h +@@ -44,7 +44,7 @@ typedef unsigned int drm_handle_t; + #else /* One of the BSDs */ + + #include +-#include ++// #include + #include + typedef int8_t __s8; + typedef uint8_t __u8; +diff --git mesa-clean/meson.build mesa-workdir/meson.build +index 2902c10..1da7605 100644 +--- mesa-clean/meson.build ++++ mesa-workdir/meson.build +@@ -959,7 +959,7 @@ if cc.has_function('fmemopen') + endif + + # TODO: this is very incomplete +-if ['linux', 'cygwin', 'gnu', 'freebsd', 'gnu/kfreebsd', 'haiku', 'android'].contains(host_machine.system()) ++if ['linux', 'cygwin', 'gnu', 'freebsd', 'gnu/kfreebsd', 'haiku', 'android', 'aero'].contains(host_machine.system()) + pre_args += '-D_GNU_SOURCE' + elif host_machine.system() == 'sunos' + pre_args += '-D__EXTENSIONS__' +diff --git mesa-clean/src/compiler/spirv/spirv_to_nir.c mesa-workdir/src/compiler/spirv/spirv_to_nir.c +index 5f36118..a501802 100644 +--- mesa-clean/src/compiler/spirv/spirv_to_nir.c ++++ mesa-workdir/src/compiler/spirv/spirv_to_nir.c +@@ -39,6 +39,7 @@ + #include "util/u_debug.h" + + #include ++#include + + #ifndef NDEBUG + uint32_t mesa_spirv_debug = 0; +diff --git mesa-clean/src/egl/main/egllog.c mesa-workdir/src/egl/main/egllog.c +index 678bb75..016a70d 100644 +--- mesa-clean/src/egl/main/egllog.c ++++ mesa-workdir/src/egl/main/egllog.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include "c11/threads.h" + #include "util/macros.h" + #include "util/simple_mtx.h" +diff --git mesa-clean/src/gallium/drivers/llvmpipe/lp_texture.c mesa-workdir/src/gallium/drivers/llvmpipe/lp_texture.c +index 5c5a6cd..ae6c23d 100644 +--- mesa-clean/src/gallium/drivers/llvmpipe/lp_texture.c ++++ mesa-workdir/src/gallium/drivers/llvmpipe/lp_texture.c +@@ -1152,7 +1152,7 @@ llvmpipe_resource_get_param(struct pipe_screen *screen, + default: + break; + } +- assert(0); ++ // assert(0); + *value = 0; + return false; + } +diff --git mesa-clean/src/util/detect_os.h mesa-workdir/src/util/detect_os.h +index 6506948..93ce551 100644 +--- mesa-clean/src/util/detect_os.h ++++ mesa-workdir/src/util/detect_os.h +@@ -28,6 +28,11 @@ + #define DETECT_OS_ANDROID 1 + #endif + ++#if defined(__aero__) ++#define DETECT_OS_AERO 1 ++#define DETECT_OS_UNIX 1 ++#endif ++ + #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + #define DETECT_OS_FREEBSD 1 + #define DETECT_OS_BSD 1 +@@ -128,4 +133,8 @@ + #define DETECT_OS_WINDOWS 0 + #endif + ++#ifndef DETECT_OS_AERO ++#define DETECT_OS_AERO 0 ++#endif ++ + #endif /* DETECT_OS_H */ +diff --git mesa-clean/src/util/futex.h mesa-workdir/src/util/futex.h +index c397507..995c1e2 100644 +--- mesa-clean/src/util/futex.h ++++ mesa-workdir/src/util/futex.h +@@ -24,7 +24,7 @@ + #ifndef UTIL_FUTEX_H + #define UTIL_FUTEX_H + +-#if defined(HAVE_LINUX_FUTEX_H) ++#if defined(HAVE_LINUX_FUTEX_H) && defined(__linux__) + #define UTIL_FUTEX_SUPPORTED 1 + #elif defined(__FreeBSD__) + #define UTIL_FUTEX_SUPPORTED 1 +diff --git mesa-clean/src/util/os_misc.c mesa-workdir/src/util/os_misc.c +index c378a9e..64f6cff 100644 +--- mesa-clean/src/util/os_misc.c ++++ mesa-workdir/src/util/os_misc.c +@@ -57,7 +57,7 @@ + # include + # include + # include +-#elif DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD ++#elif DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD || DETECT_OS_AERO + # include + #elif DETECT_OS_OPENBSD || DETECT_OS_FREEBSD + # include +@@ -248,7 +248,7 @@ exit_mutex: + bool + os_get_total_physical_memory(uint64_t *size) + { +-#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD ++#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || DETECT_OS_HURD || DETECT_OS_AERO + const long phys_pages = sysconf(_SC_PHYS_PAGES); + const long page_size = sysconf(_SC_PAGE_SIZE); + +diff --git mesa-clean/src/util/os_time.c mesa-workdir/src/util/os_time.c +index 7fb3134..38b6ade 100644 +--- mesa-clean/src/util/os_time.c ++++ mesa-workdir/src/util/os_time.c +@@ -65,7 +65,7 @@ os_time_get_nano(void) + void + os_time_sleep(int64_t usecs) + { +-#if DETECT_OS_LINUX ++#if DETECT_OS_LINUX || DETECT_OS_AERO + struct timespec time; + time.tv_sec = usecs / 1000000; + time.tv_nsec = (usecs % 1000000) * 1000; +diff --git mesa-clean/src/util/u_debug.c mesa-workdir/src/util/u_debug.c +index 61f628e..e390606 100644 +--- mesa-clean/src/util/u_debug.c ++++ mesa-workdir/src/util/u_debug.c +@@ -32,6 +32,7 @@ + #include "util/u_math.h" + #include + ++#include + #include + #include /* CHAR_BIT */ + #include /* isalnum */ +diff --git mesa-clean/src/util/u_thread.c mesa-workdir/src/util/u_thread.c +index 55b6b68..277ffbd 100644 +--- mesa-clean/src/util/u_thread.c ++++ mesa-workdir/src/util/u_thread.c +@@ -75,7 +75,7 @@ int u_thread_create(thrd_t *thrd, int (*routine)(void *), void *param) + void u_thread_setname( const char *name ) + { + #if defined(HAVE_PTHREAD) +-#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || defined(__GLIBC__) ++#if DETECT_OS_LINUX || DETECT_OS_CYGWIN || DETECT_OS_SOLARIS || defined(__GLIBC__) || DETECT_OS_AERO + int ret = pthread_setname_np(pthread_self(), name); + if (ret == ERANGE) { + char buf[16]; +@@ -154,7 +154,7 @@ util_set_thread_affinity(thrd_t thread, + int64_t + util_thread_get_time_nano(thrd_t thread) + { +-#if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) ++#if defined(HAVE_PTHREAD) && !defined(__APPLE__) && !defined(__HAIKU__) && !defined(__aero__) + struct timespec ts; + clockid_t cid; + diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch new file mode 100644 index 00000000000..e2ea7a45f2a --- /dev/null +++ b/patches/mlibc/jinx-working-patch.patch @@ -0,0 +1,164 @@ +diff --git mlibc-clean/meson.build mlibc-workdir/meson.build +index 905fbb9..6da45e0 100644 +--- mlibc-clean/meson.build ++++ mlibc-workdir/meson.build +@@ -213,7 +213,7 @@ elif host_machine.system() == 'aero' + rtld_include_dirs += include_directories('sysdeps/aero/include') + libc_include_dirs += include_directories('sysdeps/aero/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) +- internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) ++ internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', false) + subdir('sysdeps/aero') + elif host_machine.system() == 'managarm' + # TODO: Adopt the include_directories() commands from the managarm meson.build. +diff --git mlibc-clean/options/glibc/generic/execinfo.cpp mlibc-workdir/options/glibc/generic/execinfo.cpp +index 3474615..d06f130 100644 +--- mlibc-clean/options/glibc/generic/execinfo.cpp ++++ mlibc-workdir/options/glibc/generic/execinfo.cpp +@@ -1,9 +1,10 @@ + #include + #include ++#include + + int backtrace(void **, int) { +- __ensure(!"Not implemented"); +- __builtin_unreachable(); ++ mlibc::infoLogger() << "backtrace: Not implemented" << frg::endlog; ++ return 0; + } + + char **backtrace_symbols(void *const *, int) { +diff --git mlibc-clean/options/rtld/generic/linker.cpp mlibc-workdir/options/rtld/generic/linker.cpp +index b5f42af..569a8c2 100644 +--- mlibc-clean/options/rtld/generic/linker.cpp ++++ mlibc-workdir/options/rtld/generic/linker.cpp +@@ -27,7 +27,7 @@ uintptr_t libraryBase = 0x41000000; + + constexpr bool verbose = false; + constexpr bool stillSlightlyVerbose = false; +-constexpr bool logBaseAddresses = false; ++constexpr bool logBaseAddresses = true; + constexpr bool logRpath = false; + constexpr bool logLdPath = false; + constexpr bool eagerBinding = true; +@@ -470,6 +470,7 @@ frg::expected ObjectRepository::_fetchFromFile(SharedObject * + __ensure(!(object->baseAddress & (hugeSize - 1))); + + highest_address = (highest_address + mlibc::page_size - 1) & ~(mlibc::page_size - 1); ++ size_t tagSize = highest_address - object->baseAddress; + + #if MLIBC_MMAP_ALLOCATE_DSO + void *mappedAddr = nullptr; +@@ -492,9 +493,12 @@ frg::expected ObjectRepository::_fetchFromFile(SharedObject * + libraryBase += (highest_address + (hugeSize - 1)) & ~(hugeSize - 1); + #endif + +- if(verbose || logBaseAddresses) ++ if(verbose || logBaseAddresses) { ++ mlibc::sys_tag_memory((void *)object->baseAddress, tagSize, object->name.data()); ++ + mlibc::infoLogger() << "rtld: Loading " << object->name + << " at " << (void *)object->baseAddress << frg::endlog; ++ } + + // Load all segments. + constexpr size_t pageSize = 0x1000; +diff --git mlibc-clean/options/rtld/include/mlibc/rtld-sysdeps.hpp mlibc-workdir/options/rtld/include/mlibc/rtld-sysdeps.hpp +index 6f42d41..3e37a1d 100644 +--- mlibc-clean/options/rtld/include/mlibc/rtld-sysdeps.hpp ++++ mlibc-workdir/options/rtld/include/mlibc/rtld-sysdeps.hpp +@@ -5,6 +5,7 @@ namespace [[gnu::visibility("hidden")]] mlibc { + + int sys_tcb_set(void *pointer); + ++[[gnu::weak]] int sys_tag_memory(void *ptr, size_t size, char *tag); + [[gnu::weak]] int sys_vm_readahead(void *pointer, size_t size); + + } // namespace mlibc +diff --git mlibc-clean/sysdeps/aero/generic/aero.cpp mlibc-workdir/sysdeps/aero/generic/aero.cpp +index 80f9c6f..85031cd 100644 +--- mlibc-clean/sysdeps/aero/generic/aero.cpp ++++ mlibc-workdir/sysdeps/aero/generic/aero.cpp +@@ -62,6 +62,10 @@ static frg::vector create_slice(char *const arg[]) { + } + + namespace mlibc { ++int sys_tag_memory(void *ptr, size_t size, char *tag) { ++ return syscall(SYS_DEBUG, ptr, size, tag, strlen(tag)); ++} ++ + int sys_uname(struct utsname *buf) { + auto result = syscall(SYS_UNAME, buf); + +@@ -200,14 +204,19 @@ int sys_getcwd(char *buffer, size_t size) { + return 0; + } + +-int sys_chdir(const char *path) { +- auto result = syscall(SYS_CHDIR, path, strlen(path)); ++static int sys_chdir_impl(int fd, const char *path) { ++ auto ret = syscall(SYS_CHDIR, fd, path, strlen(path)); ++ if(int e = sc_error(ret); e) ++ return e; ++ return 0; ++} + +- if (result < 0) { +- return -result; +- } ++int sys_chdir(const char *path) { ++ return sys_chdir_impl(AT_FDCWD, path); ++} + +- return 0; ++int sys_fchdir(int fd) { ++ return sys_chdir_impl(fd, ""); + } + + int sys_gethostname(char *buffer, size_t bufsize) { +diff --git mlibc-clean/sysdeps/aero/generic/filesystem.cpp mlibc-workdir/sysdeps/aero/generic/filesystem.cpp +index 95c49b9..8777468 100644 +--- mlibc-clean/sysdeps/aero/generic/filesystem.cpp ++++ mlibc-workdir/sysdeps/aero/generic/filesystem.cpp +@@ -69,13 +69,14 @@ int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + } + + int sys_open(const char *filename, int flags, mode_t mode, int *fd) { +- auto result = syscall(SYS_OPEN, 0, filename, strlen(filename), flags); +- +- if (result < 0) { +- return -result; +- } ++ return sys_openat(AT_FDCWD, filename, flags, mode, fd); ++} + +- *fd = result; ++int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { ++ auto ret = syscall(SYS_OPEN, dirfd, path, strlen(path), flags, mode); ++ if (int e = sc_error(ret); e) ++ return e; ++ *fd = ret; + return 0; + } + +@@ -124,6 +125,20 @@ int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + return 0; + } + ++int sys_statfs(const char *path, struct statfs *buf) { ++ __ensure(!syscall(SYS_BACKTRACE)); ++ __ensure(!"statfs"); ++ memset(buf, 0, sizeof(struct statfs)); ++ return 0; ++} ++ ++int sys_fstatfs(int fd, struct statfs *buf) { ++ __ensure(!syscall(SYS_BACKTRACE)); ++ mlibc::infoLogger() << "fstatfs" << frg::endlog; ++ memset(buf, 0, sizeof(struct statfs)); ++ return 0; ++} ++ + int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto sys_res = syscall(SYS_IOCTL, fd, request, arg); + diff --git a/patches/mlibc/mlibc.patch b/patches/mlibc/mlibc.patch deleted file mode 100644 index 145a0362b16..00000000000 --- a/patches/mlibc/mlibc.patch +++ /dev/null @@ -1,493 +0,0 @@ -From 0eb5403c389aaa7144d6bea297aac57d442bc9f6 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Fri, 8 Jul 2022 12:32:32 +1000 -Subject: [PATCH] yes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 2 + - options/ansi/generic/stdlib-stubs.cpp | 142 +++++++++++++++++++++----- - options/glibc/generic/execinfo.cpp | 5 +- - options/rtdl/generic/linker.cpp | 2 +- - sysdeps/aero/generic/aero.cpp | 38 +++---- - sysdeps/aero/generic/filesystem.cpp | 25 ++++- - sysdeps/aero/generic/sockets.cpp | 77 +++++++++++++- - sysdeps/aero/generic/time.cpp | 24 +++++ - sysdeps/aero/include/aero/syscall.h | 6 ++ - sysdeps/aero/meson.build | 1 + - 10 files changed, 268 insertions(+), 54 deletions(-) - create mode 100644 sysdeps/aero/generic/time.cpp - -diff --git a/.gitignore b/.gitignore -index fdd60a00..9f811f47 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -3,3 +3,5 @@ subprojects - *.xbstrap - # editor configs: - .vscode -+# clangd cache files: -+.cache -diff --git a/options/ansi/generic/stdlib-stubs.cpp b/options/ansi/generic/stdlib-stubs.cpp -index 4836391e..2a73c6d0 100644 ---- a/options/ansi/generic/stdlib-stubs.cpp -+++ b/options/ansi/generic/stdlib-stubs.cpp -@@ -375,32 +375,122 @@ int mblen(const char *mbs, size_t mb_limit) { - return nseq.it - mbs; - } - --int mbtowc(wchar_t *__restrict wc, const char *__restrict mb, size_t max_size) { -- auto cc = mlibc::current_charcode(); -- __ensure(max_size); -- -- if (mb) { -- if (*mb) { -- // If wc is NULL, decode into a single local character which we discard -- // to obtain the length. -- wchar_t tmp_wc; -- if (!wc) -- wc = &tmp_wc; -- -- mlibc::code_seq wseq{wc, wc + 1}; -- mlibc::code_seq nseq{mb, mb + max_size}; -- auto e = cc->decode_wtranscode(nseq, wseq, mbtowc_state); -- if (e != mlibc::charcode_error::null) -- __ensure(!"decode_wtranscode() errors are not handled"); -- -- return nseq.it - mb; -- } else { -- return 0; // When mbs is a null byte, return 0 -- } -- } else { -- mblen_state = __MLIBC_MBSTATE_INITIALIZER; -- return cc->has_shift_states; -- } -+// int mbtowc(wchar_t *__restrict wc, const char *__restrict mb, size_t max_size) { -+// auto cc = mlibc::current_charcode(); -+// __ensure(max_size); -+// -+// if (mb) { -+// if (*mb) { -+// // If wc is NULL, decode into a single local character which we discard -+// // to obtain the length. -+// wchar_t tmp_wc; -+// if (!wc) -+// wc = &tmp_wc; -+// -+// mlibc::code_seq wseq{wc, wc + 1}; -+// mlibc::code_seq nseq{mb, mb + max_size}; -+// auto e = cc->decode_wtranscode(nseq, wseq, mbtowc_state); -+// if (e != mlibc::charcode_error::null) -+// __ensure(!"decode_wtranscode() errors are not handled"); -+// -+// return nseq.it - mb; -+// } else { -+// return 0; // When mbs is a null byte, return 0 -+// } -+// } else { -+// mblen_state = __MLIBC_MBSTATE_INITIALIZER; -+// return cc->has_shift_states; -+// } -+// } -+ -+// Upper 6 state bits are a negative integer offset to bound-check next byte -+// equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f -+#define OOB(c, b) (((((b) >> 3) - 0x10) | (((b) >> 3) + ((int32_t)(c) >> 26))) & ~7) -+ -+// Interval [a,b]. Either a must be 80 or b must be c0, lower 3 bits clear. -+#define R(a, b) ((uint32_t)((a == 0x80 ? 0x40u - b : 0u - a) << 23)) -+#define FAILSTATE R(0x80, 0x80) -+ -+#define SA 0xc2u -+#define SB 0xf4u -+ -+// Arbitrary encoding for representing code units instead of characters. -+#define CODEUNIT(c) (0xdfff & (signed char)(c)) -+#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80) -+ -+#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) ) -+#define D(x) C((x+16)) -+#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \ -+ x==0xd ? R(0x80,0xa0) : \ -+ R(0x80,0xc0) ) \ -+ | ( R(0x80,0xc0) >> 6 ) \ -+ | x ) -+#define F(x) ( ( x>=5 ? 0 : \ -+ x==0 ? R(0x90,0xc0) : \ -+ x==4 ? R(0x80,0xa0) : \ -+ R(0x80,0xc0) ) \ -+ | ( R(0x80,0xc0) >> 6 ) \ -+ | ( R(0x80,0xc0) >> 12 ) \ -+ | x ) -+ -+const uint32_t bittab[] = { -+ C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7), -+ C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf), -+ D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7), -+ D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf), -+ E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7), -+ E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf), -+ F(0x0),F(0x1),F(0x2),F(0x3),F(0x4) -+}; -+ -+// Converts a multibyte sequence to a wide character. -+// -+// Credits - MUSL -+int mbtowc(wchar_t *__restrict wc, const char *__restrict src, size_t n) { -+ unsigned c; -+ const unsigned char *s = static_cast((const void *)src); -+ wchar_t dummy; -+ -+ if (!s) return 0; -+ if (!n) goto ilseq; -+ if (!wc) wc = &dummy; -+ -+ if (*s < 0x80) return !!(*wc = *s); -+ if (MB_CUR_MAX == 1) return (*wc = CODEUNIT(*s)), 1; -+ if (*s - SA > SB - SA) goto ilseq; -+ -+ c = bittab[*s++ - SA]; -+ -+ // Avoid excessive checks against n: If shifting the state n-1 -+ // times does not clear the high bit, then the value of n is -+ // insufficient to read a character. -+ if (n < 4 && ((c << (6 * n - 6)) & (1U << 31))) goto ilseq; -+ if (OOB(c, *s)) goto ilseq; -+ -+ c = c << 6 | (*s++ - 0x80); -+ -+ if (!(c & (1U << 31))) { -+ *wc = c; -+ return 2; -+ } -+ -+ if (*s - 0x80u >= 0x40) goto ilseq; -+ -+ c = c << 6 | (*s++ - 0x80); -+ -+ if (!(c & (1U << 31))) { -+ *wc = c; -+ return 3; -+ } -+ -+ if (*s - 0x80u >= 0x40) goto ilseq; -+ -+ *wc = c << 6 | (*s++ - 0x80); -+ return 4; -+ -+ilseq: -+ errno = EILSEQ; -+ return -1; - } - - int wctomb(char *, wchar_t) { -diff --git a/options/glibc/generic/execinfo.cpp b/options/glibc/generic/execinfo.cpp -index 3474615e..10a2109e 100644 ---- a/options/glibc/generic/execinfo.cpp -+++ b/options/glibc/generic/execinfo.cpp -@@ -1,9 +1,10 @@ - #include - #include -+#include - - int backtrace(void **, int) { -- __ensure(!"Not implemented"); -- __builtin_unreachable(); -+ mlibc::infoLogger() << "backtrace() is unimplemented" << frg::endlog; -+ return 0; - } - - char **backtrace_symbols(void *const *, int) { -diff --git a/options/rtdl/generic/linker.cpp b/options/rtdl/generic/linker.cpp -index 6716ef4f..e5ec8cff 100644 ---- a/options/rtdl/generic/linker.cpp -+++ b/options/rtdl/generic/linker.cpp -@@ -15,7 +15,7 @@ uintptr_t libraryBase = 0x41000000; - - constexpr bool verbose = false; - constexpr bool stillSlightlyVerbose = false; --constexpr bool logBaseAddresses = false; -+constexpr bool logBaseAddresses = true; - constexpr bool logRpath = false; - constexpr bool eagerBinding = true; - -diff --git a/sysdeps/aero/generic/aero.cpp b/sysdeps/aero/generic/aero.cpp -index 29fb9610..a27da559 100644 ---- a/sysdeps/aero/generic/aero.cpp -+++ b/sysdeps/aero/generic/aero.cpp -@@ -69,22 +69,22 @@ int sys_futex_tid() { - } - - int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { -- auto result = syscall(SYS_FUTEX_WAIT, pointer, expected, time); -- -- if (result < 0) { -- return -result; -- } -- -+ // auto result = syscall(SYS_FUTEX_WAIT, pointer, expected, time); -+ // -+ // if (result < 0) { -+ // return -result; -+ // } -+ // - return 0; - } - - int sys_futex_wake(int *pointer) { -- auto result = syscall(SYS_FUTEX_WAKE, pointer); -- -- if (result < 0) { -- return -result; -- } -- -+ // auto result = syscall(SYS_FUTEX_WAKE, pointer); -+ // -+ // if (result < 0) { -+ // return -result; -+ // } -+ // - return 0; - } - -@@ -124,7 +124,9 @@ int sys_anon_free(void *pointer, size_t size) { - } - - void sys_libc_panic() { -- sys_libc_log("libc panic!"); -+ mlibc::infoLogger() << "libc_panic: panicked at 'unknown'" << frg::endlog; -+ __ensure(!syscall(SYS_BACKTRACE)); -+ - sys_exit(1); - } - -@@ -233,7 +235,7 @@ uid_t sys_geteuid() { - return 0; - } - --int sys_setuid(uid_t uid) UNIMPLEMENTED("sys_setuid") -+// int sys_setuid(uid_t uid) UNIMPLEMENTED("sys_setuid") - int sys_seteuid(uid_t euid) UNIMPLEMENTED("sys_seteuid") - - gid_t sys_getgid() { -@@ -259,13 +261,13 @@ int sys_setegid(gid_t egid) { - void sys_yield() UNIMPLEMENTED("sys_yield") - - int sys_clone(void *tcb, pid_t *tid_out, void *stack) { -- auto tid = syscall(SYS_CLONE, (uintptr_t)__mlibc_start_thread, stack); -+ auto result = syscall(SYS_CLONE, (uintptr_t)__mlibc_start_thread, stack); - -- if (tid < 0) { -- return -tid; -+ if (result < 0) { -+ return -result; - } - -- *tid_out = (pid_t)tid; -+ *tid_out = (pid_t)result; - return 0; - } - -diff --git a/sysdeps/aero/generic/filesystem.cpp b/sysdeps/aero/generic/filesystem.cpp -index a3e2aca2..4187059e 100644 ---- a/sysdeps/aero/generic/filesystem.cpp -+++ b/sysdeps/aero/generic/filesystem.cpp -@@ -158,11 +158,6 @@ int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { - return 0; - } - --int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { -- mlibc::infoLogger() << "sys_poll() is not implemented" << frg::endlog; -- return 0; --} -- - int sys_mkdir(const char *path, mode_t) { - auto result = syscall(SYS_MKDIR, path, strlen(path)); - -@@ -357,4 +352,24 @@ int sys_eventfd_create(unsigned int initval, int flags, int *fd) { - *fd = result; - return 0; - } -+ -+int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, -+ const sigset_t *sigmask, int *num_events) { -+ auto result = syscall(SYS_POLL, fds, nfds, timeout, sigmask); -+ -+ if (result < 0) { -+ return -result; -+ } -+ -+ *num_events = result; -+ return 0; -+} -+ -+int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { -+ struct timespec ts; -+ ts.tv_sec = timeout / 1000; -+ ts.tv_nsec = (timeout % 1000) * 1000000; -+ -+ return sys_ppoll(fds, count, &ts, NULL, num_events); -+} - } // namespace mlibc -diff --git a/sysdeps/aero/generic/sockets.cpp b/sysdeps/aero/generic/sockets.cpp -index b6b18fe7..e03c634b 100644 ---- a/sysdeps/aero/generic/sockets.cpp -+++ b/sysdeps/aero/generic/sockets.cpp -@@ -1,5 +1,6 @@ - #include - #include -+#include - - #include - #include -@@ -46,8 +47,8 @@ int sys_listen(int fd, int backlog) { - return 0; - } - --int sys_accept(int fd, int *newfd) { -- auto result = syscall(SYS_ACCEPT, fd); -+int sys_accept(int sockfd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length) { -+ auto result = syscall(SYS_ACCEPT, sockfd, addr_ptr, addr_length); - - if (result < 0) { - return -result; -@@ -56,4 +57,76 @@ int sys_accept(int fd, int *newfd) { - *newfd = result; - return 0; - } -+ -+ -+int sys_msg_recv(int sockfd, struct msghdr *msg_hdr, int flags, ssize_t *length) { -+ auto result = syscall(SYS_SOCK_RECV, sockfd, msg_hdr, flags); -+ -+ if (result < 0) { -+ return -result; -+ } -+ -+ *length = result; -+ return 0; -+} -+ -+int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { -+ (void)fd; (void)size; -+ if (layer == SOL_SOCKET && number == SO_PEERCRED) { -+ mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_PEERCRED is unimplemented\e[39m" << frg::endlog; -+ *(int *)buffer = 0; -+ return 0; -+ } else if(layer == SOL_SOCKET && number == SO_SNDBUF) { -+ mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; -+ *(int *)buffer = 4096; -+ return 0; -+ } else if(layer == SOL_SOCKET && number == SO_TYPE) { -+ mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is unimplemented, hardcoding SOCK_STREAM\e[39m" << frg::endlog; -+ *(int *)buffer = SOCK_STREAM; -+ return 0; -+ } else if(layer == SOL_SOCKET && number == SO_ERROR) { -+ mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is unimplemented, hardcoding 0\e[39m" << frg::endlog; -+ *(int *)buffer = 0; -+ return 0; -+ } else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { -+ mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" << frg::endlog; -+ *(int *)buffer = 0; -+ return 0; -+ } else{ -+ mlibc::panicLogger() << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; -+ __builtin_unreachable(); -+ } -+ -+ return 0; -+} -+ -+int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { -+ (void)fd; (void)buffer; (void)size; -+ -+ if (layer == SOL_SOCKET && number == SO_PASSCRED) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_PASSCRED) is not implemented correctly\e[39m" << frg::endlog; -+ return 0; -+ } else if (layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is not implemented correctly\e[39m" << frg::endlog; -+ return 0; -+ } else if (layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not implemented correctly\e[39m" << frg::endlog; -+ return 0; -+ } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; -+ return 0; -+ } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented\e[39m" << frg::endlog; -+ return 0; -+ } else if (layer == SOL_SOCKET && number == SO_REUSEADDR) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEADDR is unimplemented\e[39m" << frg::endlog; -+ return 0; -+ } else if (layer == AF_NETLINK && number == SO_ACCEPTCONN) { -+ mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with AF_NETLINK and SO_ACCEPTCONN is unimplemented\e[39m" << frg::endlog; -+ return 0; -+ } else { -+ mlibc::panicLogger() << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; -+ __builtin_unreachable(); -+ } -+} - } // namespace mlibc -diff --git a/sysdeps/aero/generic/time.cpp b/sysdeps/aero/generic/time.cpp -new file mode 100644 -index 00000000..460412d0 ---- /dev/null -+++ b/sysdeps/aero/generic/time.cpp -@@ -0,0 +1,24 @@ -+#include -+#include -+ -+namespace mlibc { -+int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { -+ auto result = syscall(SYS_SETITIMER, which, new_value, old_value); -+ -+ if (result < 0) { -+ return -result; -+ } -+ -+ return 0; -+} -+ -+int sys_getitimer(int which, struct itimerval *curr_value) { -+ auto result = syscall(SYS_GETITIMER, which, curr_value); -+ -+ if (result < 0) { -+ return -result; -+ } -+ -+ return 0; -+} -+} -\ No newline at end of file -diff --git a/sysdeps/aero/include/aero/syscall.h b/sysdeps/aero/include/aero/syscall.h -index 12f8dc61..03001c46 100644 ---- a/sysdeps/aero/include/aero/syscall.h -+++ b/sysdeps/aero/include/aero/syscall.h -@@ -64,6 +64,12 @@ - #define SYS_FUTEX_WAIT 57 - #define SYS_FUTEX_WAKE 58 - #define SYS_LINK 59 -+#define SYS_BACKTRACE 60 -+#define SYS_POLL 61 -+#define SYS_EXIT_THREAD 62 -+#define SYS_SOCK_RECV 63 -+#define SYS_SETITIMER 64 -+#define SYS_GETITIMER 65 - - // Invalid syscall used to trigger a log error in the kernel (as a hint) - // so, that we can implement the syscall in the kernel. -diff --git a/sysdeps/aero/meson.build b/sysdeps/aero/meson.build -index 3ca8463e..f1d80139 100644 ---- a/sysdeps/aero/meson.build -+++ b/sysdeps/aero/meson.build -@@ -11,6 +11,7 @@ libc_sources += files( - 'generic/filesystem.cpp', - 'generic/sockets.cpp', - 'generic/signals.cpp', -+ 'generic/time.cpp', - ) - - if not no_headers --- -2.25.1 - diff --git a/patches/ncurses/jinx-working-patch.patch b/patches/ncurses/jinx-working-patch.patch new file mode 100644 index 00000000000..7ebebf230b9 --- /dev/null +++ b/patches/ncurses/jinx-working-patch.patch @@ -0,0 +1,15 @@ +diff --git ncurses-clean/configure ncurses-workdir/configure +index d652dc0..1572ae3 100755 +--- ncurses-clean/configure ++++ ncurses-workdir/configure +@@ -6923,6 +6923,10 @@ CF_EOF + LINK_PROGS="$SHELL ${rel_builddir}/mk_prog.sh" + LINK_TESTS="$SHELL ${rel_builddir}/mk_prog.sh" + ;; ++ (aero*) ++ CC_SHARED_OPTS='-fPIC' ++ MK_SHARED_LIB='${CC} -shared -o $@' ++ ;; + (mingw*) + cf_cv_shlib_version=mingw + cf_cv_shlib_version_infix=mingw diff --git a/patches/nyancat/nyancat.patch b/patches/nyancat/nyancat.patch deleted file mode 100644 index abe6dc4956d..00000000000 --- a/patches/nyancat/nyancat.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 040f0506e6ba7093bd12a7c89fb90f99a67ad33d Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Thu, 23 Dec 2021 12:17:11 +1100 -Subject: [PATCH] targets: add aero target port - -Signed-off-by: Andy-Python-Programmer ---- - .vscode/settings.json | 6 ++++++ - src/nyancat.c | 2 -- - 2 files changed, 6 insertions(+), 2 deletions(-) - create mode 100644 .vscode/settings.json - -diff --git a/.vscode/settings.json b/.vscode/settings.json -new file mode 100644 -index 0000000..b5431d3 ---- /dev/null -+++ b/.vscode/settings.json -@@ -0,0 +1,6 @@ -+{ -+ "editor.formatOnSave": false, -+ "files.associations": { -+ "termios.h": "c" -+ }, -+} -\ No newline at end of file -diff --git a/src/nyancat.c b/src/nyancat.c -index 537225c..af77e5b 100644 ---- a/src/nyancat.c -+++ b/src/nyancat.c -@@ -67,9 +67,7 @@ - - #include - --#ifndef TIOCGWINSZ - #include --#endif - - #ifdef ECHO - #undef ECHO --- -2.25.1 - diff --git a/patches/openssl/0001-openssl-aero-specific-changes.patch b/patches/openssl/jinx-working-patch.patch similarity index 58% rename from patches/openssl/0001-openssl-aero-specific-changes.patch rename to patches/openssl/jinx-working-patch.patch index 46029c9a7f0..8f76a3937b7 100644 --- a/patches/openssl/0001-openssl-aero-specific-changes.patch +++ b/patches/openssl/jinx-working-patch.patch @@ -1,45 +1,20 @@ -From 1ddd02965f0a65b5c59e8b152229b2b88517ae2b Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Tue, 28 Jun 2022 17:33:52 +1000 -Subject: [PATCH] openssl: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 3 +++ - Configurations/10-main.conf | 33 +++++++++++++++++++++++++++++++++ - Configure | 15 +-------------- - apps/speed.c | 2 ++ - test/rsa_complex.c | 4 +++- - 5 files changed, 42 insertions(+), 15 deletions(-) - -diff --git a/.gitignore b/.gitignore -index b7bee656..673368bd 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -184,3 +184,6 @@ pod2htmd.tmp - # Windows manifest files - *.manifest - doc-nits -+ -+# editor configs: -+.vscode -diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf -index 8ca8235e..414fe92b 100644 ---- a/Configurations/10-main.conf -+++ b/Configurations/10-main.conf -@@ -918,6 +918,39 @@ my %targets = ( +diff --git openssl-clean/Configurations/10-main.conf openssl-workdir/Configurations/10-main.conf +index f815a09..d403653 100644 +--- openssl-clean/Configurations/10-main.conf ++++ openssl-workdir/Configurations/10-main.conf +@@ -925,6 +925,40 @@ my %targets = ( ranlib => "true", }, -+#### Aero ++#### Aero + "aero-generic64" => { + inherit_from => [ "BASE_unix" ], + CFLAGS => picker(default => "-Wall", -+ debug => "-O0 -g", -+ release => "-O3"), ++ debug => "-O0 -g", ++ release => "-O3"), + CXXFLAGS => picker(default => "-Wall", -+ debug => "-O0 -g", -+ release => "-O3"), ++ debug => "-O0 -g", ++ release => "-O3"), + cxxflags => add("-std=c++11"), + lib_cppflags => combine("-DOPENSSL_USE_NODELETE", "-DL_ENDIAN"), + bn_ops => "SIXTY_FOUR_BIT_LONG RC4_CHAR", @@ -52,25 +27,26 @@ index 8ca8235e..414fe92b 100644 + }, + + # This breaks the usual configuration naming convention but it's more -+ # convenient for us, since it matches the target triples. ++ # convenient for us, since it matches the target triples + + "x86_64-aero" => { + inherit_from => [ "aero-generic64", asm("x86_64_asm") ], + perlasm_scheme => "elf", + + # Configure doesn't want to play nice and passes "--cross-compile-suffix" -+ # on to the GCC invocation. ++ # on to the GCC invocation + CC => "x86_64-aero-gcc", + CXX => "x86_64-aero-g++", ++ + }, + #### *BSD "BSD-generic32" => { # As for thread cflag. Idea is to maintain "collective" set of -diff --git a/Configure b/Configure -index 4bea49d7..964793fe 100755 ---- a/Configure -+++ b/Configure +diff --git openssl-clean/Configure openssl-workdir/Configure +index 78cc15d..2d3fb3e 100755 +--- openssl-clean/Configure ++++ openssl-workdir/Configure @@ -1549,20 +1549,7 @@ unless ($disabled{"crypto-mdebug-backtrace"}) unless ($disabled{afalgeng}) { $config{afalgeng}=""; @@ -93,10 +69,10 @@ index 4bea49d7..964793fe 100755 } else { disable('not-linux', 'afalgeng'); } -diff --git a/apps/speed.c b/apps/speed.c -index 89bf1848..74322241 100644 ---- a/apps/speed.c -+++ b/apps/speed.c +diff --git openssl-clean/apps/speed.c openssl-workdir/apps/speed.c +index 89bf184..7432224 100644 +--- openssl-clean/apps/speed.c ++++ openssl-workdir/apps/speed.c @@ -113,6 +113,8 @@ # define NO_FORK #endif @@ -106,21 +82,33 @@ index 89bf1848..74322241 100644 #define MAX_MISALIGNMENT 63 #define MAX_ECDH_SIZE 256 #define MISALIGN 64 -diff --git a/test/rsa_complex.c b/test/rsa_complex.c -index fac58125..4c7aeeef 100644 ---- a/test/rsa_complex.c -+++ b/test/rsa_complex.c +diff --git openssl-clean/crypto/mem_sec.c openssl-workdir/crypto/mem_sec.c +index 222c786..edb5192 100644 +--- openssl-clean/crypto/mem_sec.c ++++ openssl-workdir/crypto/mem_sec.c +@@ -492,8 +492,10 @@ static int sh_init(size_t size, int minsize) + ret = 2; + #endif + #ifdef MADV_DONTDUMP ++/* + if (madvise(sh.arena, sh.arena_size, MADV_DONTDUMP) < 0) + ret = 2; ++*/ + #endif + + return ret; +diff --git openssl-clean/test/rsa_complex.c openssl-workdir/test/rsa_complex.c +index fac5812..a23670d 100644 +--- openssl-clean/test/rsa_complex.c ++++ openssl-workdir/test/rsa_complex.c @@ -14,7 +14,9 @@ */ #if defined(__STDC_VERSION__) # if __STDC_VERSION__ >= 199901L -# include -+# if !defined(__aero) ++# if !defined(__aero__) +# include +# endif # endif #endif #include --- -2.25.1 - diff --git a/patches/python/jinx-working-patch.patch b/patches/python/jinx-working-patch.patch new file mode 100644 index 00000000000..b26ff6d122b --- /dev/null +++ b/patches/python/jinx-working-patch.patch @@ -0,0 +1,54 @@ +diff --git python-clean/configure.ac python-workdir/configure.ac +index cd69f0e..74fc416 100644 +--- python-clean/configure.ac ++++ python-workdir/configure.ac +@@ -553,6 +553,9 @@ then + *-*-cygwin*) + ac_sys_system=Cygwin + ;; ++ *-*-aero*) ++ ac_sys_system=Aero ++ ;; + *-*-vxworks*) + ac_sys_system=VxWorks + ;; +@@ -619,6 +622,9 @@ if test "$cross_compiling" = yes; then + *-*-vxworks*) + _host_cpu=$host_cpu + ;; ++ *-*-aero*) ++ _host_cpu=$host_cpu ++ ;; + wasm32-*-* | wasm64-*-*) + _host_cpu=$host_cpu + ;; +@@ -3216,6 +3222,9 @@ then + CYGWIN*) + LDSHARED="gcc -shared -Wl,--enable-auto-image-base" + LDCXXSHARED="g++ -shared -Wl,--enable-auto-image-base";; ++ Aero*) ++ LDSHARED='$(CC) -shared' ++ LDCXXSHARED='$(CXX) - shared';; + *) LDSHARED="ld";; + esac + fi +@@ -3268,7 +3277,9 @@ then + else CCSHARED="-Kpic -belf" + fi;; + VxWorks*) +- CCSHARED="-fpic -D__SO_PICABILINUX__ -ftls-model=global-dynamic" ++ CCSHARED="-fpic -D__SO_PICABILINUX__ -ftls-model=global-dynamic";; ++ Aero*) ++ CCSHARED="-fPIC";; + esac + fi + AC_MSG_RESULT([$CCSHARED]) +@@ -3338,6 +3349,8 @@ then + LINKFORSHARED='-Wl,-E -N 2048K';; + VxWorks*) + LINKFORSHARED='-Wl,-export-dynamic';; ++ Aero*) ++ LINKFORSHARED='-export-dynamic';; + esac + fi + AC_MSG_RESULT([$LINKFORSHARED]) diff --git a/patches/python/python.patch b/patches/python/python.patch deleted file mode 100644 index b30d30cddac..00000000000 --- a/patches/python/python.patch +++ /dev/null @@ -1,81 +0,0 @@ -From d413109d47cba4c05c48ff959850bef39bd1630e Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Sun, 2 Jan 2022 13:01:40 +1100 -Subject: [PATCH] config: add aero target - -Signed-off-by: Andy-Python-Programmer ---- - config.sub | 2 +- - configure.ac | 15 ++++++++++++++- - 2 files changed, 15 insertions(+), 2 deletions(-) - -diff --git a/config.sub b/config.sub -index ba37cf9..cea962e 100755 ---- a/config.sub -+++ b/config.sub -@@ -1394,7 +1394,7 @@ case $os in - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ -- | -midnightbsd*) -+ | -midnightbsd* | -aero*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) -diff --git a/configure.ac b/configure.ac -index e57ef7c..d686b36 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -379,6 +379,9 @@ then - *-*-cygwin*) - ac_sys_system=Cygwin - ;; -+ *-*-aero*) -+ ac_sys_system=Aero -+ ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -431,6 +434,9 @@ if test "$cross_compiling" = yes; then - *-*-vxworks*) - _host_cpu=$host_cpu - ;; -+ *-*-aero*) -+ _host_cpu=$host_cpu -+ ;; - *) - # for now, limit cross builds to known configurations - MACHDEP="unknown" -@@ -2641,6 +2647,9 @@ then - CYGWIN*) - LDSHARED="gcc -shared -Wl,--enable-auto-image-base" - LDCXXSHARED="g++ -shared -Wl,--enable-auto-image-base";; -+ Aero*) -+ LDSHARED='$(CC) -shared' -+ LDCXXSHARED='$(CXX) -shared';; - *) LDSHARED="ld";; - esac - fi -@@ -2677,7 +2686,9 @@ then - else CCSHARED="-Kpic -belf" - fi;; - VxWorks*) -- CCSHARED="-fpic -D__SO_PICABILINUX__ -ftls-model=global-dynamic" -+ CCSHARED="-fpic -D__SO_PICABILINUX__ -ftls-model=global-dynamic";; -+ Aero*) -+ CCSHARED="-fPIC";; - esac - fi - AC_MSG_RESULT($CCSHARED) -@@ -2738,6 +2749,8 @@ then - LINKFORSHARED='-Wl,-E -N 2048K';; - VxWorks*) - LINKFORSHARED='--export-dynamic';; -+ Aero*) -+ LINKFORSHARED='-export-dynamic';; - esac - fi - AC_MSG_RESULT($LINKFORSHARED) --- -2.25.1 - diff --git a/patches/quickjs/quickjs.patch b/patches/quickjs/quickjs.patch deleted file mode 100644 index c348b716ebb..00000000000 --- a/patches/quickjs/quickjs.patch +++ /dev/null @@ -1,86 +0,0 @@ -From e6336a3d82e80205e1dd91dc08cf92e7d40393a5 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Thu, 13 Jan 2022 14:53:32 +1100 -Subject: [PATCH] aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .vscode/settings.json | 3 +++ - qjs.c | 4 ++++ - quickjs-libc.c | 4 ++++ - quickjs.c | 4 ++++ - 4 files changed, 15 insertions(+) - create mode 100644 .vscode/settings.json - -diff --git a/.vscode/settings.json b/.vscode/settings.json -new file mode 100644 -index 0000000..560faaa ---- /dev/null -+++ b/.vscode/settings.json -@@ -0,0 +1,3 @@ -+{ -+ "editor.formatOnSave": false, -+} -\ No newline at end of file -diff --git a/qjs.c b/qjs.c -index d56b843..de8308a 100644 ---- a/qjs.c -+++ b/qjs.c -@@ -148,6 +148,8 @@ static inline size_t js_trace_malloc_usable_size(void *ptr) - return _msize(ptr); - #elif defined(EMSCRIPTEN) - return 0; -+#elif defined(__aero__) -+ return 0; // TODO: (Aero): This is totally wrong. - #elif defined(__linux__) - return malloc_usable_size(ptr); - #else -@@ -270,6 +272,8 @@ static const JSMallocFunctions trace_mf = { - (size_t (*)(const void *))_msize, - #elif defined(EMSCRIPTEN) - NULL, -+#elif defined(__aero__) -+ NULL, // TODO: (Aero): This is totally wrong. - #elif defined(__linux__) - (size_t (*)(const void *))malloc_usable_size, - #else -diff --git a/quickjs-libc.c b/quickjs-libc.c -index e180dd0..45313fd 100644 ---- a/quickjs-libc.c -+++ b/quickjs-libc.c -@@ -57,6 +57,10 @@ typedef sig_t sighandler_t; - - #endif - -+#if defined(__aero__) -+typedef void (*sighandler_t)(int); -+#endif -+ - #if !defined(_WIN32) - /* enable the os.Worker API. IT relies on POSIX threads */ - #define USE_WORKER -diff --git a/quickjs.c b/quickjs.c -index 48aeffc..8922b67 100644 ---- a/quickjs.c -+++ b/quickjs.c -@@ -1682,6 +1682,8 @@ static inline size_t js_def_malloc_usable_size(void *ptr) - return _msize(ptr); - #elif defined(EMSCRIPTEN) - return 0; -+#elif defined(__aero__) -+ return 0; // TODO: (Aero) this is totally wrong :^) - #elif defined(__linux__) - return malloc_usable_size(ptr); - #else -@@ -1756,6 +1758,8 @@ static const JSMallocFunctions def_malloc_funcs = { - (size_t (*)(const void *))_msize, - #elif defined(EMSCRIPTEN) - NULL, -+#elif defined(__aero__) -+ NULL, // TODO: (Aero) this is totally wrong :^) - #elif defined(__linux__) - (size_t (*)(const void *))malloc_usable_size, - #else --- -2.25.1 - diff --git a/patches/readline/jinx-working-patch.patch b/patches/readline/jinx-working-patch.patch new file mode 100644 index 00000000000..7de35244a74 --- /dev/null +++ b/patches/readline/jinx-working-patch.patch @@ -0,0 +1,22 @@ +diff --git readline-clean/support/shlib-install readline-workdir/support/shlib-install +index 661355d..cd7d659 100755 +--- readline-clean/support/shlib-install ++++ readline-workdir/support/shlib-install +@@ -71,7 +71,7 @@ fi + # Cygwin installs both a dll (which must go in $BINDIR) and an implicit + # link library (in $libdir) + case "$host_os" in +-hpux*|darwin*|macosx*|linux*|solaris2*) ++hpux*|darwin*|macosx*|linux*|solaris2*|aero*) + if [ -z "$uninstall" ]; then + chmod 755 ${INSTALLDIR}/${LIBNAME} + fi ;; +@@ -146,7 +146,7 @@ bsdi4*|*gnu*|darwin*|macosx*|netbsd*|mirbsd*) + fi + ;; + +-solaris2*|aix4.[2-9]*|aix[5-9]*|osf*|irix[56]*|sysv[45]*|dgux*|interix*) ++solaris2*|aix4.[2-9]*|aix[5-9]*|osf*|irix[56]*|sysv[45]*|dgux*|interix*|aero*) + # libname.so -> libname.so.M + ${echo} ${RM} ${INSTALLDIR}/$LINK1 + if [ -z "$uninstall" ]; then diff --git a/patches/rust-host/jinx-working-patch.patch b/patches/rust-host/jinx-working-patch.patch new file mode 100644 index 00000000000..84643abf5f3 --- /dev/null +++ b/patches/rust-host/jinx-working-patch.patch @@ -0,0 +1,531 @@ +diff --git rust-host-clean/Cargo.toml rust-host-workdir/Cargo.toml +index 9b11ae8..2d310ce 100644 +--- rust-host-clean/Cargo.toml ++++ rust-host-workdir/Cargo.toml +@@ -110,6 +110,7 @@ object.debug = 0 + rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' } + rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' } + rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } ++libc = { path = "/base_dir/sources/rust-libc" } + + [patch."https://github.com/rust-lang/rust-clippy"] + clippy_lints = { path = "src/tools/clippy/clippy_lints" } +diff --git rust-host-workdir/compiler/rustc_target/src/spec/base/aero.rs rust-host-workdir/compiler/rustc_target/src/spec/base/aero.rs +new file mode 100644 +index 0000000..1237a43 +--- /dev/null ++++ rust-host-workdir/compiler/rustc_target/src/spec/base/aero.rs +@@ -0,0 +1,34 @@ ++use crate::spec::{cvs, LinkArgs, LinkerFlavor, RelroLevel, TargetOptions, Cc, Lld}; ++ ++pub fn opts() -> TargetOptions { ++ let mut args = LinkArgs::new(); ++ args.insert( ++ LinkerFlavor::Gnu(Cc::Yes, Lld::No), ++ vec![ ++ // We want to be able to strip as much executable code as possible ++ // from the linker command line, and this flag indicates to the ++ // linker that it can avoid linking in dynamic libraries that don't ++ // actually satisfy any symbols up to that point (as with many other ++ // resolutions the linker does). This option only applies to all ++ // following libraries so we're sure to pass it as one of the first ++ // arguments. ++ "-Wl,--as-needed".into(), ++ // Always enable NX protection when it is available ++ "-Wl,-z,noexecstack".into(), ++ ], ++ ); ++ ++ TargetOptions { ++ os: "aero".into(), ++ dynamic_linking: true, ++ executables: true, ++ families: cvs!["unix"], ++ has_rpath: true, ++ pre_link_args: args, ++ position_independent_executables: true, ++ relro_level: RelroLevel::Full, ++ has_thread_local: true, ++ crt_static_respected: true, ++ ..Default::default() ++ } ++} +diff --git rust-host-clean/compiler/rustc_target/src/spec/base/mod.rs rust-host-workdir/compiler/rustc_target/src/spec/base/mod.rs +index d137aaa..6f52f4a 100644 +--- rust-host-clean/compiler/rustc_target/src/spec/base/mod.rs ++++ rust-host-workdir/compiler/rustc_target/src/spec/base/mod.rs +@@ -1,3 +1,4 @@ ++pub(crate) mod aero; + pub(crate) mod aix; + pub(crate) mod android; + pub(crate) mod apple; +diff --git rust-host-clean/compiler/rustc_target/src/spec/mod.rs rust-host-workdir/compiler/rustc_target/src/spec/mod.rs +index f047994..83be01f 100644 +--- rust-host-clean/compiler/rustc_target/src/spec/mod.rs ++++ rust-host-workdir/compiler/rustc_target/src/spec/mod.rs +@@ -1556,6 +1556,8 @@ supported_targets! { + ("x86_64-fuchsia", x86_64_fuchsia), + ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), + ++ ("x86_64-unknown-aero", x86_64_unknown_aero), ++ + ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), + + ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), +diff --git rust-host-workdir/compiler/rustc_target/src/spec/targets/x86_64_unknown_aero.rs rust-host-workdir/compiler/rustc_target/src/spec/targets/x86_64_unknown_aero.rs +new file mode 100644 +index 0000000..b88491e +--- /dev/null ++++ rust-host-workdir/compiler/rustc_target/src/spec/targets/x86_64_unknown_aero.rs +@@ -0,0 +1,20 @@ ++use crate::spec::{base, LinkerFlavor, StackProbeType, Target, Cc, Lld}; ++ ++pub fn target() -> Target { ++ let mut base = base::aero::opts(); ++ base.cpu = "x86-64".into(); ++ base.max_atomic_width = Some(64); ++ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); ++ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved. ++ base.stack_probes = StackProbeType::Call; ++ ++ Target { ++ // Should we use "aero" or "aero-mlibc" here? ++ llvm_target: "x86_64-aero".into(), ++ pointer_width: 64, ++ data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" ++ .into(), ++ arch: "x86_64".into(), ++ options: base, ++ } ++} +diff --git rust-host-clean/library/std/build.rs rust-host-workdir/library/std/build.rs +index ad0a82e..14488d7 100644 +--- rust-host-clean/library/std/build.rs ++++ rust-host-workdir/library/std/build.rs +@@ -4,6 +4,7 @@ fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let target = env::var("TARGET").expect("TARGET was not set"); + if target.contains("linux") ++ || target.contains("aero") + || target.contains("netbsd") + || target.contains("dragonfly") + || target.contains("openbsd") +diff --git rust-host-workdir/library/std/src/os/aero/fs.rs rust-host-workdir/library/std/src/os/aero/fs.rs +new file mode 100644 +index 0000000..a3c953c +--- /dev/null ++++ rust-host-workdir/library/std/src/os/aero/fs.rs +@@ -0,0 +1,144 @@ ++#![stable(feature = "raw_ext", since = "1.1.0")] ++ ++use crate::fs::Metadata; ++use crate::sys_common::AsInner; ++ ++#[allow(deprecated)] ++use crate::os::aero::raw; ++ ++/// OS-specific extensions to [`fs::Metadata`]. ++/// ++/// [`fs::Metadata`]: crate::fs::Metadata ++#[stable(feature = "metadata_ext", since = "1.1.0")] ++pub trait MetadataExt { ++ /// Gain a reference to the underlying `stat` structure which contains ++ /// the raw information returned by the OS. ++ /// ++ /// The contents of the returned `stat` are **not** consistent across ++ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the ++ /// cross-Unix abstractions contained within the raw stat. ++ #[stable(feature = "metadata_ext", since = "1.1.0")] ++ #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")] ++ #[allow(deprecated)] ++ fn as_raw_stat(&self) -> &raw::stat; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_dev(&self) -> u64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_ino(&self) -> u64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_mode(&self) -> u32; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_nlink(&self) -> u64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_uid(&self) -> u32; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_gid(&self) -> u32; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_rdev(&self) -> u64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_size(&self) -> u64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_atime(&self) -> i64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_atime_nsec(&self) -> i64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_mtime(&self) -> i64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_mtime_nsec(&self) -> i64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_ctime(&self) -> i64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_ctime_nsec(&self) -> i64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_blksize(&self) -> u64; ++ ++ #[stable(feature = "metadata_ext2", since = "1.8.0")] ++ fn st_blocks(&self) -> u64; ++} ++ ++#[stable(feature = "metadata_ext", since = "1.1.0")] ++impl MetadataExt for Metadata { ++ #[allow(deprecated)] ++ fn as_raw_stat(&self) -> &raw::stat { ++ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } ++ } ++ ++ fn st_dev(&self) -> u64 { ++ self.as_inner().as_inner().st_dev as u64 ++ } ++ ++ fn st_ino(&self) -> u64 { ++ self.as_inner().as_inner().st_ino as u64 ++ } ++ ++ fn st_mode(&self) -> u32 { ++ self.as_inner().as_inner().st_mode as u32 ++ } ++ ++ fn st_nlink(&self) -> u64 { ++ self.as_inner().as_inner().st_nlink as u64 ++ } ++ ++ fn st_uid(&self) -> u32 { ++ self.as_inner().as_inner().st_uid as u32 ++ } ++ ++ fn st_gid(&self) -> u32 { ++ self.as_inner().as_inner().st_gid as u32 ++ } ++ ++ fn st_rdev(&self) -> u64 { ++ self.as_inner().as_inner().st_rdev as u64 ++ } ++ ++ fn st_size(&self) -> u64 { ++ self.as_inner().as_inner().st_size as u64 ++ } ++ ++ fn st_atime(&self) -> i64 { ++ self.as_inner().as_inner().st_atime as i64 ++ } ++ ++ fn st_atime_nsec(&self) -> i64 { ++ self.as_inner().as_inner().st_atime_nsec as i64 ++ } ++ ++ fn st_mtime(&self) -> i64 { ++ self.as_inner().as_inner().st_mtime as i64 ++ } ++ ++ fn st_mtime_nsec(&self) -> i64 { ++ self.as_inner().as_inner().st_mtime_nsec as i64 ++ } ++ ++ fn st_ctime(&self) -> i64 { ++ self.as_inner().as_inner().st_ctime as i64 ++ } ++ ++ fn st_ctime_nsec(&self) -> i64 { ++ self.as_inner().as_inner().st_ctime_nsec as i64 ++ } ++ ++ fn st_blksize(&self) -> u64 { ++ self.as_inner().as_inner().st_blksize as u64 ++ } ++ ++ fn st_blocks(&self) -> u64 { ++ self.as_inner().as_inner().st_blocks as u64 ++ } ++} +diff --git rust-host-workdir/library/std/src/os/aero/mod.rs rust-host-workdir/library/std/src/os/aero/mod.rs +new file mode 100644 +index 0000000..ea3291a +--- /dev/null ++++ rust-host-workdir/library/std/src/os/aero/mod.rs +@@ -0,0 +1,6 @@ ++//! Aero-specific definitions ++ ++#![stable(feature = "raw_ext", since = "1.1.0")] ++ ++pub mod fs; ++pub mod raw; +diff --git rust-host-workdir/library/std/src/os/aero/raw.rs rust-host-workdir/library/std/src/os/aero/raw.rs +new file mode 100644 +index 0000000..0569409 +--- /dev/null ++++ rust-host-workdir/library/std/src/os/aero/raw.rs +@@ -0,0 +1,76 @@ ++//! Aero-specific raw type definitions ++ ++#![stable(feature = "raw_ext", since = "1.1.0")] ++#![deprecated( ++ since = "1.8.0", ++ note = "these type aliases are no longer supported by \ ++ the standard library, the `libc` crate on \ ++ crates.io should be used instead for the correct \ ++ definitions" ++)] ++#![allow(deprecated)] ++ ++#[stable(feature = "pthread_t", since = "1.8.0")] ++pub type pthread_t = usize; // TODO: This is completely wrong tbh ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type dev_t = libc::dev_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type ino_t = libc::ino_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type mode_t = libc::mode_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type nlink_t = libc::nlink_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type off_t = libc::off_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type time_t = libc::time_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type blkcnt_t = libc::blkcnt_t; ++ ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub type blksize_t = libc::blksize_t; ++ ++#[repr(C)] ++#[derive(Clone)] ++#[stable(feature = "raw_ext", since = "1.1.0")] ++pub struct stat { ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_dev: libc::dev_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_ino: libc::ino_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_mode: libc::mode_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_nlink: libc::nlink_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_uid: libc::uid_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_gid: libc::gid_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_rdev: libc::dev_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_size: libc::off_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_atime: libc::time_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_atime_nsec: libc::c_long, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_mtime: libc::time_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_mtime_nsec: libc::c_long, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_ctime: libc::time_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_ctime_nsec: libc::c_long, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_blksize: libc::blksize_t, ++ #[stable(feature = "raw_ext", since = "1.1.0")] ++ pub st_blocks: libc::blkcnt_t, ++} +diff --git rust-host-clean/library/std/src/os/mod.rs rust-host-workdir/library/std/src/os/mod.rs +index 6e11b92..96ba192 100644 +--- rust-host-clean/library/std/src/os/mod.rs ++++ rust-host-workdir/library/std/src/os/mod.rs +@@ -113,6 +113,8 @@ pub mod fortanix_sgx; + pub mod freebsd; + #[cfg(target_os = "fuchsia")] + pub mod fuchsia; ++#[cfg(target_os = "aero")] ++pub mod aero; + #[cfg(target_os = "haiku")] + pub mod haiku; + #[cfg(target_os = "hermit")] +diff --git rust-host-clean/library/std/src/os/unix/mod.rs rust-host-workdir/library/std/src/os/unix/mod.rs +index 5ba8719..21d5e8d 100644 +--- rust-host-clean/library/std/src/os/unix/mod.rs ++++ rust-host-workdir/library/std/src/os/unix/mod.rs +@@ -37,6 +37,8 @@ use crate::os::linux as platform; + + #[cfg(not(doc))] + mod platform { ++ #[cfg(target_os = "aero")] ++ pub use crate::os::aero::*; + #[cfg(target_os = "aix")] + pub use crate::os::aix::*; + #[cfg(target_os = "android")] +@@ -95,7 +97,11 @@ pub mod process; + pub mod raw; + pub mod thread; + +-#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] ++#[unstable( ++ feature = "peer_credentials_unix_socket", ++ issue = "42839", ++ reason = "unstable" ++)] + #[cfg(any( + target_os = "android", + target_os = "linux", +diff --git rust-host-clean/library/std/src/sys/unix/args.rs rust-host-workdir/library/std/src/sys/unix/args.rs +index 2da17fa..a1bdb2c 100644 +--- rust-host-clean/library/std/src/sys/unix/args.rs ++++ rust-host-workdir/library/std/src/sys/unix/args.rs +@@ -73,6 +73,7 @@ impl DoubleEndedIterator for Args { + target_os = "aix", + target_os = "nto", + target_os = "hurd", ++ target_os = "aero", + ))] + mod imp { + use super::Args; +diff --git rust-host-clean/library/std/src/sys/unix/env.rs rust-host-workdir/library/std/src/sys/unix/env.rs +index 3bb492f..1a680fa 100644 +--- rust-host-clean/library/std/src/sys/unix/env.rs ++++ rust-host-workdir/library/std/src/sys/unix/env.rs +@@ -1,3 +1,14 @@ ++#[cfg(target_os = "aero")] ++pub mod os { ++ pub const FAMILY: &str = "unix"; ++ pub const OS: &str = "aero"; ++ pub const DLL_PREFIX: &str = "lib"; ++ pub const DLL_SUFFIX: &str = ".so"; ++ pub const DLL_EXTENSION: &str = ""; ++ pub const EXE_SUFFIX: &str = ""; ++ pub const EXE_EXTENSION: &str = ""; ++} ++ + #[cfg(target_os = "linux")] + pub mod os { + pub const FAMILY: &str = "unix"; +diff --git rust-host-clean/library/std/src/sys/unix/fs.rs rust-host-workdir/library/std/src/sys/unix/fs.rs +index 40eb910..994558c 100644 +--- rust-host-clean/library/std/src/sys/unix/fs.rs ++++ rust-host-workdir/library/std/src/sys/unix/fs.rs +@@ -954,6 +954,7 @@ impl DirEntry { + target_os = "aix", + target_os = "nto", + target_os = "hurd", ++ target_os = "aero", + ))] + pub fn ino(&self) -> u64 { + self.entry.d_ino as u64 +diff --git rust-host-clean/library/std/src/sys/unix/os.rs rust-host-workdir/library/std/src/sys/unix/os.rs +index dc3c037..0b405a8 100644 +--- rust-host-clean/library/std/src/sys/unix/os.rs ++++ rust-host-workdir/library/std/src/sys/unix/os.rs +@@ -40,7 +40,7 @@ cfg_if::cfg_if! { + } + + extern "C" { +- #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] ++ #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "aero")))] + #[cfg_attr( + any( + target_os = "linux", +@@ -79,18 +79,46 @@ extern "C" { + } + + /// Returns the platform-specific value of errno +-#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] ++#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "aero")))] + pub fn errno() -> i32 { + unsafe { (*errno_location()) as i32 } + } + + /// Sets the platform-specific value of errno +-#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! ++#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "aero")))] // needed for readdir and syscall! + #[allow(dead_code)] // but not all target cfgs actually end up using it + pub fn set_errno(e: i32) { + unsafe { *errno_location() = e as c_int } + } + ++#[cfg(target_os = "aero")] ++pub fn errno() -> i32 { ++ extern "C" { ++ #[thread_local] ++ static __mlibc_errno: c_int; ++ } ++ ++ unsafe { __mlibc_errno as i32 } ++} ++ ++#[cfg(target_os = "aero")] ++#[allow(dead_code)] ++pub fn set_errno(e: i32) { ++ extern "C" { ++ #[thread_local] ++ static mut __mlibc_errno: c_int; ++ } ++ ++ unsafe { ++ __mlibc_errno = e; ++ } ++} ++ ++#[cfg(target_os = "aero")] ++pub fn current_exe() -> io::Result { ++ unimplemented!() ++} ++ + #[cfg(target_os = "vxworks")] + pub fn errno() -> i32 { + unsafe { libc::errnoGet() } +diff --git rust-host-clean/library/std/src/sys/unix/thread.rs rust-host-workdir/library/std/src/sys/unix/thread.rs +index 29db946..d8b595d 100644 +--- rust-host-clean/library/std/src/sys/unix/thread.rs ++++ rust-host-workdir/library/std/src/sys/unix/thread.rs +@@ -116,6 +116,13 @@ impl Thread { + debug_assert_eq!(ret, 0); + } + ++ #[cfg(target_os = "aero")] ++ pub fn set_name(name: &CStr) { ++ unsafe { ++ libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); ++ } ++ } ++ + #[cfg(target_os = "android")] + pub fn set_name(name: &CStr) { + const PR_SET_NAME: libc::c_int = 15; +diff --git rust-host-clean/library/std/src/sys/unix/thread_local_dtor.rs rust-host-workdir/library/std/src/sys/unix/thread_local_dtor.rs +index 06399e8..297032e 100644 +--- rust-host-clean/library/std/src/sys/unix/thread_local_dtor.rs ++++ rust-host-workdir/library/std/src/sys/unix/thread_local_dtor.rs +@@ -12,7 +12,7 @@ + // compiling from a newer linux to an older linux, so we also have a + // fallback implementation to use as well. + #[allow(unexpected_cfgs)] +-#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))] ++#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd", target_os = "aero"))] + // FIXME: The Rust compiler currently omits weakly function definitions (i.e., + // __cxa_thread_atexit_impl) and its metadata from LLVM IR. + #[no_sanitize(cfi, kcfi)] diff --git a/patches/rust-num-cpus/rust-num-cpus.patch b/patches/rust-num-cpus/rust-num-cpus.patch deleted file mode 100644 index 8ab20459c41..00000000000 --- a/patches/rust-num-cpus/rust-num-cpus.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 69bdbf9a09b403cac206f0dba50663ebf1e161d9 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Wed, 12 Jan 2022 17:19:55 +1100 -Subject: [PATCH] aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - src/lib.rs | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/lib.rs b/src/lib.rs -index 6c8280f..e87efa8 100644 ---- a/src/lib.rs -+++ b/src/lib.rs -@@ -331,7 +331,8 @@ fn get_num_physical_cpus() -> usize { - target_os = "android", - target_os = "solaris", - target_os = "illumos", -- target_os = "fuchsia") -+ target_os = "fuchsia", -+ target_os = "aero") - )] - fn get_num_cpus() -> usize { - // On ARM targets, processors could be turned off to save power. -@@ -420,6 +421,7 @@ fn get_num_cpus() -> usize { - target_os = "netbsd", - target_os = "haiku", - target_os = "hermit", -+ target_os = "aero", - windows, - )))] - fn get_num_cpus() -> usize { --- -2.25.1 - diff --git a/patches/rust-users/rust-users.patch b/patches/rust-users/rust-users.patch deleted file mode 100644 index da45496c7bc..00000000000 --- a/patches/rust-users/rust-users.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0dcaffa14eb80d3a8d1236a09d0bd2f28326c6db Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Wed, 12 Jan 2022 17:23:53 +1100 -Subject: [PATCH] aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - src/base.rs | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/base.rs b/src/base.rs -index ece499a..fc5f3cb 100644 ---- a/src/base.rs -+++ b/src/base.rs -@@ -923,7 +923,7 @@ pub mod os { - /// Although the `passwd` struct is common among Unix systems, its actual - /// format can vary. See the definitions in the `base` module to check which - /// fields are actually present. -- #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd", target_os = "solaris"))] -+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd", target_os = "solaris", target_os = "aero"))] - pub mod unix { - use std::ffi::{OsStr, OsString}; - use std::path::{Path, PathBuf}; -@@ -1176,11 +1176,11 @@ pub mod os { - pub type UserExtras = bsd::UserExtras; - - /// Any extra fields on a `User` specific to the current platform. -- #[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))] -+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris", target_os = "aero"))] - pub type UserExtras = unix::UserExtras; - - /// Any extra fields on a `Group` specific to the current platform. -- #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd", target_os = "solaris"))] -+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd", target_os = "solaris", target_os = "aero"))] - pub type GroupExtras = unix::GroupExtras; - } - --- -2.25.1 - diff --git a/patches/rust/rust.patch b/patches/rust/rust.patch deleted file mode 100644 index 2928a43e403..00000000000 --- a/patches/rust/rust.patch +++ /dev/null @@ -1,687 +0,0 @@ -From 13f0d6bc6ed1ccf0155e27be832ec121cf138b85 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Wed, 12 Jan 2022 15:57:15 +1100 -Subject: [PATCH] targets: add aero target and port std to it - -Signed-off-by: Andy-Python-Programmer ---- - Cargo.lock | 4 +- - Cargo.toml | 1 + - .../rustc_target/src/spec/aero_system_base.rs | 35 +++++ - compiler/rustc_target/src/spec/mod.rs | 3 + - .../src/spec/x86_64_unknown_aero_system.rs | 19 +++ - library/std/build.rs | 1 + - library/std/src/os/aero/fs.rs | 148 ++++++++++++++++++ - library/std/src/os/aero/mod.rs | 6 + - library/std/src/os/aero/raw.rs | 66 ++++++++ - library/std/src/os/mod.rs | 2 + - library/std/src/os/unix/mod.rs | 2 + - library/std/src/sys/unix/args.rs | 3 +- - library/std/src/sys/unix/env.rs | 11 ++ - library/std/src/sys/unix/fs.rs | 6 +- - library/std/src/sys/unix/os.rs | 39 ++++- - library/std/src/sys/unix/thread.rs | 7 + - library/std/src/sys/unix/thread_local_dtor.rs | 3 +- - library/std/src/sys/unix/time.rs | 7 +- - library/unwind/build.rs | 2 + - src/bootstrap/bootstrap.py | 8 +- - src/bootstrap/builder.rs | 6 +- - 21 files changed, 359 insertions(+), 20 deletions(-) - create mode 100644 compiler/rustc_target/src/spec/aero_system_base.rs - create mode 100644 compiler/rustc_target/src/spec/x86_64_unknown_aero_system.rs - create mode 100644 library/std/src/os/aero/fs.rs - create mode 100644 library/std/src/os/aero/mod.rs - create mode 100644 library/std/src/os/aero/raw.rs - -diff --git a/Cargo.lock b/Cargo.lock -index ef9f91fd..e303ef85 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -1950,9 +1950,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - - [[package]] - name = "libc" --version = "0.2.108" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" -+version = "0.2.125" - dependencies = [ - "rustc-std-workspace-core", - ] -diff --git a/Cargo.toml b/Cargo.toml -index cae48d79..a3328ea6 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -130,6 +130,7 @@ rustc-workspace-hack = { path = 'src/tools/rustc-workspace-hack' } - rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' } - rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' } - rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } -+libc = { path = '../rust-libc' } - - [patch."https://github.com/rust-lang/rust-clippy"] - clippy_lints = { path = "src/tools/clippy/clippy_lints" } -diff --git a/compiler/rustc_target/src/spec/aero_system_base.rs b/compiler/rustc_target/src/spec/aero_system_base.rs -new file mode 100644 -index 00000000..795047af ---- /dev/null -+++ b/compiler/rustc_target/src/spec/aero_system_base.rs -@@ -0,0 +1,35 @@ -+use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; -+ -+pub fn opts() -> TargetOptions { -+ let mut args = LinkArgs::new(); -+ args.insert( -+ LinkerFlavor::Gcc, -+ vec![ -+ // We want to be able to strip as much executable code as possible -+ // from the linker command line, and this flag indicates to the -+ // linker that it can avoid linking in dynamic libraries that don't -+ // actually satisfy any symbols up to that point (as with many other -+ // resolutions the linker does). This option only applies to all -+ // following libraries so we're sure to pass it as one of the first -+ // arguments. -+ "-Wl,--as-needed".to_string(), -+ // Always enable NX protection when it is available -+ "-Wl,-z,noexecstack".to_string(), -+ ], -+ ); -+ -+ TargetOptions { -+ os: "aero".to_string(), -+ dynamic_linking: true, -+ executables: true, -+ families: vec!["unix".to_string()], -+ linker_is_gnu: true, -+ has_rpath: true, -+ pre_link_args: args, -+ position_independent_executables: true, -+ relro_level: RelroLevel::Full, -+ has_thread_local: true, -+ crt_static_respected: true, -+ ..Default::default() -+ } -+} -diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs -index 2c149318..81c93277 100644 ---- a/compiler/rustc_target/src/spec/mod.rs -+++ b/compiler/rustc_target/src/spec/mod.rs -@@ -62,6 +62,7 @@ - mod freebsd_base; - mod fuchsia_base; - mod haiku_base; -+mod aero_system_base; - mod hermit_base; - mod hermit_kernel_base; - mod illumos_base; -@@ -889,6 +890,8 @@ fn $module() { - ("i686-unknown-haiku", i686_unknown_haiku), - ("x86_64-unknown-haiku", x86_64_unknown_haiku), - -+ ("x86_64-unknown-aero-system", x86_64_unknown_aero_system), -+ - ("aarch64-apple-darwin", aarch64_apple_darwin), - ("x86_64-apple-darwin", x86_64_apple_darwin), - ("i686-apple-darwin", i686_apple_darwin), -diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_aero_system.rs b/compiler/rustc_target/src/spec/x86_64_unknown_aero_system.rs -new file mode 100644 -index 00000000..51c44ef8 ---- /dev/null -+++ b/compiler/rustc_target/src/spec/x86_64_unknown_aero_system.rs -@@ -0,0 +1,19 @@ -+use crate::spec::{LinkerFlavor, StackProbeType, Target}; -+ -+pub fn target() -> Target { -+ let mut base = super::aero_system_base::opts(); -+ base.cpu = "x86-64".to_string(); -+ base.max_atomic_width = Some(64); -+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); -+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved. -+ base.stack_probes = StackProbeType::Call; -+ -+ Target { -+ llvm_target: "x86_64-unknown-aero-system".to_string(), -+ pointer_width: 64, -+ data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" -+ .to_string(), -+ arch: "x86_64".to_string(), -+ options: base, -+ } -+} -diff --git a/library/std/build.rs b/library/std/build.rs -index 43168e77..5a6e296c 100644 ---- a/library/std/build.rs -+++ b/library/std/build.rs -@@ -23,6 +23,7 @@ fn main() { - || target.contains("l4re") - || target.contains("redox") - || target.contains("haiku") -+ || target.contains("aero") - || target.contains("vxworks") - || target.contains("wasm32") - || target.contains("wasm64") -diff --git a/library/std/src/os/aero/fs.rs b/library/std/src/os/aero/fs.rs -new file mode 100644 -index 00000000..412bbc44 ---- /dev/null -+++ b/library/std/src/os/aero/fs.rs -@@ -0,0 +1,148 @@ -+#![stable(feature = "raw_ext", since = "1.1.0")] -+ -+use crate::fs::Metadata; -+use crate::sys_common::AsInner; -+ -+#[allow(deprecated)] -+use crate::os::aero::raw; -+ -+/// OS-specific extensions to [`fs::Metadata`]. -+/// -+/// [`fs::Metadata`]: crate::fs::Metadata -+#[stable(feature = "metadata_ext", since = "1.1.0")] -+pub trait MetadataExt { -+ /// Gain a reference to the underlying `stat` structure which contains -+ /// the raw information returned by the OS. -+ /// -+ /// The contents of the returned `stat` are **not** consistent across -+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the -+ /// cross-Unix abstractions contained within the raw stat. -+ #[stable(feature = "metadata_ext", since = "1.1.0")] -+ #[rustc_deprecated( -+ since = "1.8.0", -+ reason = "deprecated in favor of the accessor \ -+ methods of this trait" -+ )] -+ #[allow(deprecated)] -+ fn as_raw_stat(&self) -> &raw::stat; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_dev(&self) -> u64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_ino(&self) -> u64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_mode(&self) -> u32; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_nlink(&self) -> u64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_uid(&self) -> u32; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_gid(&self) -> u32; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_rdev(&self) -> u64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_size(&self) -> u64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_atime(&self) -> i64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_atime_nsec(&self) -> i64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_mtime(&self) -> i64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_mtime_nsec(&self) -> i64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_ctime(&self) -> i64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_ctime_nsec(&self) -> i64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_blksize(&self) -> u64; -+ -+ #[stable(feature = "metadata_ext2", since = "1.8.0")] -+ fn st_blocks(&self) -> u64; -+} -+ -+#[stable(feature = "metadata_ext", since = "1.1.0")] -+impl MetadataExt for Metadata { -+ #[allow(deprecated)] -+ fn as_raw_stat(&self) -> &raw::stat { -+ unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } -+ } -+ -+ fn st_dev(&self) -> u64 { -+ self.as_inner().as_inner().st_dev as u64 -+ } -+ -+ fn st_ino(&self) -> u64 { -+ self.as_inner().as_inner().st_ino as u64 -+ } -+ -+ fn st_mode(&self) -> u32 { -+ self.as_inner().as_inner().st_mode as u32 -+ } -+ -+ fn st_nlink(&self) -> u64 { -+ self.as_inner().as_inner().st_nlink as u64 -+ } -+ -+ fn st_uid(&self) -> u32 { -+ self.as_inner().as_inner().st_uid as u32 -+ } -+ -+ fn st_gid(&self) -> u32 { -+ self.as_inner().as_inner().st_gid as u32 -+ } -+ -+ fn st_rdev(&self) -> u64 { -+ self.as_inner().as_inner().st_rdev as u64 -+ } -+ -+ fn st_size(&self) -> u64 { -+ self.as_inner().as_inner().st_size as u64 -+ } -+ -+ fn st_atime(&self) -> i64 { -+ self.as_inner().as_inner().st_atime as i64 -+ } -+ -+ fn st_atime_nsec(&self) -> i64 { -+ self.as_inner().as_inner().st_atime_nsec as i64 -+ } -+ -+ fn st_mtime(&self) -> i64 { -+ self.as_inner().as_inner().st_mtime as i64 -+ } -+ -+ fn st_mtime_nsec(&self) -> i64 { -+ self.as_inner().as_inner().st_mtime_nsec as i64 -+ } -+ -+ fn st_ctime(&self) -> i64 { -+ self.as_inner().as_inner().st_ctime as i64 -+ } -+ -+ fn st_ctime_nsec(&self) -> i64 { -+ self.as_inner().as_inner().st_ctime_nsec as i64 -+ } -+ -+ fn st_blksize(&self) -> u64 { -+ self.as_inner().as_inner().st_blksize as u64 -+ } -+ -+ fn st_blocks(&self) -> u64 { -+ self.as_inner().as_inner().st_blocks as u64 -+ } -+} -diff --git a/library/std/src/os/aero/mod.rs b/library/std/src/os/aero/mod.rs -new file mode 100644 -index 00000000..ea3291a2 ---- /dev/null -+++ b/library/std/src/os/aero/mod.rs -@@ -0,0 +1,6 @@ -+//! Aero-specific definitions -+ -+#![stable(feature = "raw_ext", since = "1.1.0")] -+ -+pub mod fs; -+pub mod raw; -diff --git a/library/std/src/os/aero/raw.rs b/library/std/src/os/aero/raw.rs -new file mode 100644 -index 00000000..c5e56b8b ---- /dev/null -+++ b/library/std/src/os/aero/raw.rs -@@ -0,0 +1,66 @@ -+#![stable(feature = "raw_ext", since = "1.1.0")] -+ -+#[stable(feature = "pthread_t", since = "1.8.0")] -+pub type pthread_t = usize; // TODO: This is completely wrong tbh -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type dev_t = libc::dev_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type ino_t = libc::ino_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type mode_t = libc::mode_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type nlink_t = libc::nlink_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type off_t = libc::off_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type time_t = libc::time_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type blkcnt_t = libc::blkcnt_t; -+ -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub type blksize_t = libc::blksize_t; -+ -+#[repr(C)] -+#[derive(Clone)] -+#[stable(feature = "raw_ext", since = "1.1.0")] -+pub struct stat { -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_dev: libc::dev_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_ino: libc::ino_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_mode: libc::mode_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_nlink: libc::nlink_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_uid: libc::uid_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_gid: libc::gid_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_rdev: libc::dev_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_size: libc::off_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_atime: libc::time_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_atime_nsec: libc::c_long, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_mtime: libc::time_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_mtime_nsec: libc::c_long, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_ctime: libc::time_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_ctime_nsec: libc::c_long, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_blksize: libc::blksize_t, -+ #[stable(feature = "raw_ext", since = "1.1.0")] -+ pub st_blocks: libc::blkcnt_t, -+} -diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs -index 90c30313..bf76ad34 100644 ---- a/library/std/src/os/mod.rs -+++ b/library/std/src/os/mod.rs -@@ -129,6 +129,8 @@ pub mod windows {} - pub mod ios; - #[cfg(target_os = "macos")] - pub mod macos; -+#[cfg(target_os = "aero")] -+pub mod aero; - #[cfg(target_os = "netbsd")] - pub mod netbsd; - #[cfg(target_os = "openbsd")] -diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs -index 62f750fa..a69d31b5 100644 ---- a/library/std/src/os/unix/mod.rs -+++ b/library/std/src/os/unix/mod.rs -@@ -37,6 +37,8 @@ - - #[cfg(not(doc))] - mod platform { -+ #[cfg(target_os = "aero")] -+ pub use crate::os::aero::*; - #[cfg(target_os = "android")] - pub use crate::os::android::*; - #[cfg(target_os = "dragonfly")] -diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs -index ee5e3983..5ad752ab 100644 ---- a/library/std/src/sys/unix/args.rs -+++ b/library/std/src/sys/unix/args.rs -@@ -68,7 +68,8 @@ fn next_back(&mut self) -> Option { - target_os = "l4re", - target_os = "fuchsia", - target_os = "redox", -- target_os = "vxworks" -+ target_os = "vxworks", -+ target_os = "aero" - ))] - mod imp { - use super::Args; -diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs -index 60551aeb..fabb5e63 100644 ---- a/library/std/src/sys/unix/env.rs -+++ b/library/std/src/sys/unix/env.rs -@@ -195,3 +195,14 @@ pub mod os { - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; - } -+ -+#[cfg(target_os = "aero")] -+pub mod os { -+ pub const FAMILY: &str = "unix"; -+ pub const OS: &str = "aero"; -+ pub const DLL_PREFIX: &str = "lib"; -+ pub const DLL_SUFFIX: &str = ".so"; -+ pub const DLL_EXTENSION: &str = "so"; -+ pub const EXE_SUFFIX: &str = ""; -+ pub const EXE_EXTENSION: &str = ""; -+} -diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs -index bcf2be0e..f523f5c5 100644 ---- a/library/std/src/sys/unix/fs.rs -+++ b/library/std/src/sys/unix/fs.rs -@@ -612,7 +612,8 @@ pub fn file_type(&self) -> io::Result { - target_os = "fuchsia", - target_os = "redox", - target_os = "vxworks", -- target_os = "espidf" -+ target_os = "espidf", -+ target_os = "aero" - ))] - pub fn ino(&self) -> u64 { - self.entry.d_ino as u64 -@@ -652,7 +653,8 @@ fn name_bytes(&self) -> &[u8] { - target_os = "l4re", - target_os = "haiku", - target_os = "vxworks", -- target_os = "espidf" -+ target_os = "espidf", -+ target_os = "aero" - ))] - fn name_bytes(&self) -> &[u8] { - unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } -diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs -index 8a028d99..7e0a25f8 100644 ---- a/library/std/src/sys/unix/os.rs -+++ b/library/std/src/sys/unix/os.rs -@@ -39,7 +39,7 @@ - } - - extern "C" { -- #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] -+ #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "aero")))] - #[cfg_attr( - any( - target_os = "linux", -@@ -69,13 +69,18 @@ - } - - /// Returns the platform-specific value of errno --#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] -+#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "aero")))] - pub fn errno() -> i32 { - unsafe { (*errno_location()) as i32 } - } - - /// Sets the platform-specific value of errno --#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! -+#[cfg(all( -+ not(target_os = "linux"), -+ not(target_os = "dragonfly"), -+ not(target_os = "vxworks"), -+ not(target_os = "aero") -+))] // needed for readdir and syscall! - #[allow(dead_code)] // but not all target cfgs actually end up using it - pub fn set_errno(e: i32) { - unsafe { *errno_location() = e as c_int } -@@ -109,6 +114,29 @@ pub fn set_errno(e: i32) { - } - } - -+#[cfg(target_os = "aero")] -+pub fn errno() -> i32 { -+ extern "C" { -+ #[thread_local] -+ static __mlibc_errno: c_int; -+ } -+ -+ unsafe { __mlibc_errno as i32 } -+} -+ -+#[cfg(target_os = "aero")] -+#[allow(dead_code)] -+pub fn set_errno(e: i32) { -+ extern "C" { -+ #[thread_local] -+ static mut __mlibc_errno: c_int; -+ } -+ -+ unsafe { -+ __mlibc_errno = e; -+ } -+} -+ - /// Gets a detailed string description for the given error number. - pub fn error_string(errno: i32) -> String { - extern "C" { -@@ -454,6 +482,11 @@ pub fn current_exe() -> io::Result { - super::unsupported::unsupported() - } - -+#[cfg(target_os = "aero")] -+pub fn current_exe() -> io::Result { -+ unimplemented!() -+} -+ - pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, - } -diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs -index 9e02966b..b6e326d8 100644 ---- a/library/std/src/sys/unix/thread.rs -+++ b/library/std/src/sys/unix/thread.rs -@@ -140,6 +140,13 @@ pub fn set_name(name: &CStr) { - } - } - -+ #[cfg(target_os = "aero")] -+ pub fn set_name(name: &CStr) { -+ unsafe { -+ libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); -+ } -+ } -+ - #[cfg(target_os = "netbsd")] - pub fn set_name(name: &CStr) { - use crate::ffi::CString; -diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs -index c3f41035..cf0139b1 100644 ---- a/library/std/src/sys/unix/thread_local_dtor.rs -+++ b/library/std/src/sys/unix/thread_local_dtor.rs -@@ -15,7 +15,8 @@ - target_os = "linux", - target_os = "fuchsia", - target_os = "redox", -- target_os = "emscripten" -+ target_os = "emscripten", -+ target_os = "aero" - ))] - pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - use crate::mem; -diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs -index 824283ef..de405297 100644 ---- a/library/std/src/sys/unix/time.rs -+++ b/library/std/src/sys/unix/time.rs -@@ -362,12 +362,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - } - } - -- #[cfg(not(any(target_os = "dragonfly", target_os = "espidf")))] -- pub type clock_t = libc::c_int; -- #[cfg(any(target_os = "dragonfly", target_os = "espidf"))] -- pub type clock_t = libc::c_ulong; -- -- fn now(clock: clock_t) -> Timespec { -+ fn now(clock: libc::clockid_t) -> Timespec { - let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }; - cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap(); - t -diff --git a/library/unwind/build.rs b/library/unwind/build.rs -index a3f52241..2e3bf0d3 100644 ---- a/library/unwind/build.rs -+++ b/library/unwind/build.rs -@@ -46,5 +46,7 @@ fn main() { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("redox") { - // redox is handled in lib.rs -+ } else if target.contains("aero") { -+ println!("cargo:rustc-link-lib=gcc_s"); - } - } -diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py -index 7c36bb26..c22ac54c 100644 ---- a/src/bootstrap/bootstrap.py -+++ b/src/bootstrap/bootstrap.py -@@ -972,7 +972,7 @@ class RustBuild(object): - ... "debug", "bootstrap") - True - """ -- return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap") -+ return os.path.join(self.build_dir, "bootstrap", self.build, "debug", "bootstrap") - - def build_bootstrap(self): - """Build bootstrap""" -@@ -981,7 +981,7 @@ class RustBuild(object): - if self.clean and os.path.exists(build_dir): - shutil.rmtree(build_dir) - env = os.environ.copy() -- # `CARGO_BUILD_TARGET` breaks bootstrap build. -+ # `CARGO_BUILD_TARGET` and 'build.target' break bootstrap build. - # See also: . - if "CARGO_BUILD_TARGET" in env: - del env["CARGO_BUILD_TARGET"] -@@ -1028,6 +1028,10 @@ class RustBuild(object): - args.append("--locked") - if self.use_vendored_sources: - args.append("--frozen") -+ -+ args.append("--target") -+ args.append(self.build) -+ - run(args, env=env, verbose=self.verbose) - - def build_triple(self): -diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs -index 6ccf8b1d..0bbe8685 100644 ---- a/src/bootstrap/builder.rs -+++ b/src/bootstrap/builder.rs -@@ -1120,6 +1120,8 @@ pub fn cargo( - self.clear_if_dirty(&out_dir, &self.rustc(compiler)); - } - -+ let artifact_dir = self.out.join("bootstrap/").join(self.build.build.triple).join("debug/"); -+ - // Customize the compiler we're running. Specify the compiler to cargo - // as our shim and then pass it some various options used to configure - // how the actual compiler itself is called. -@@ -1132,7 +1134,7 @@ pub fn cargo( - .env("RUSTC_STAGE", stage.to_string()) - .env("RUSTC_SYSROOT", &sysroot) - .env("RUSTC_LIBDIR", &libdir) -- .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) -+ .env("RUSTDOC", artifact_dir.join("rustdoc")) - .env( - "RUSTDOC_REAL", - if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) { -@@ -1146,7 +1148,7 @@ pub fn cargo( - // Clippy support is a hack and uses the default `cargo-clippy` in path. - // Don't override RUSTC so that the `cargo-clippy` in path will be run. - if cmd != "clippy" { -- cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")); -+ cargo.env("RUSTC", artifact_dir.join("rustc")); - } - - // Dealing with rpath here is a little special, so let's go into some --- -2.25.1 - diff --git a/patches/tcc/tcc.patch b/patches/tcc/tcc.patch deleted file mode 100644 index 914fb2e4828..00000000000 --- a/patches/tcc/tcc.patch +++ /dev/null @@ -1,166 +0,0 @@ -From d6759f3711877792de6eae84616f0077c5089b1e Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Fri, 31 Dec 2021 17:14:30 +1100 -Subject: [PATCH] add support for aero - -Signed-off-by: Andy-Python-Programmer ---- - .vscode/settings.json | 3 +++ - configure | 2 +- - include/stdarg.h | 6 ++++++ - lib/Makefile | 8 ++++---- - libtcc.c | 4 ++-- - tcc.c | 4 +++- - tcc.h | 4 ++++ - tccelf.c | 2 ++ - 8 files changed, 25 insertions(+), 8 deletions(-) - create mode 100644 .vscode/settings.json - -diff --git a/.vscode/settings.json b/.vscode/settings.json -new file mode 100644 -index 0000000..560faaa ---- /dev/null -+++ b/.vscode/settings.json -@@ -0,0 +1,3 @@ -+{ -+ "editor.formatOnSave": false, -+} -\ No newline at end of file -diff --git a/configure b/configure -index 1ee3acb..cab20ed 100755 ---- a/configure -+++ b/configure -@@ -49,7 +49,7 @@ gcc_major=0 - gcc_minor=0 - - # OS specific --targetos=`uname` -+targetos=Aero - case $targetos in - Darwin) - confvars="$confvars OSX" -diff --git a/include/stdarg.h b/include/stdarg.h -index 10ce733..405ac68 100644 ---- a/include/stdarg.h -+++ b/include/stdarg.h -@@ -1,6 +1,10 @@ - #ifndef _STDARG_H - #define _STDARG_H - -+#ifdef __need___va_list -+typedef char *__gnuc_va_list; -+#else -+ - #ifdef __x86_64__ - #ifndef _WIN64 - -@@ -76,4 +80,6 @@ typedef char *va_list; - typedef va_list __gnuc_va_list; - #define _VA_LIST_DEFINED - -+#endif -+ - #endif /* _STDARG_H */ -diff --git a/lib/Makefile b/lib/Makefile -index 0c1ec54..c546dff 100644 ---- a/lib/Makefile -+++ b/lib/Makefile -@@ -20,18 +20,18 @@ XCFG = $(or $(findstring -win,$T),-unx) - # in order to use gcc, tyoe: make -libtcc1-usegcc=yes - arm-libtcc1-usegcc ?= no - --ifeq "$($(T)-libtcc1-usegcc)" "yes" -+#ifeq "$($(T)-libtcc1-usegcc)" "yes" - XCC = $(CC) - XAR = $(AR) - XFLAGS = $(CFLAGS) -fPIC --endif -+#endif - - # only for native compiler - $(X)BCHECK_O = bcheck.o - --ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes) -+#ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes) - BCHECK_O = --endif -+#endif - - ifdef CONFIG_OSX - XFLAGS += -D_ANSI_SOURCE -diff --git a/libtcc.c b/libtcc.c -index 1e9dd97..30d27f0 100644 ---- a/libtcc.c -+++ b/libtcc.c -@@ -975,8 +975,8 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) - if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && - !s->nostdlib) { - if (output_type != TCC_OUTPUT_DLL) -- tcc_add_crt(s, "crt1.o"); -- tcc_add_crt(s, "crti.o"); -+ tcc_add_crt(s, "crt0.o"); -+ //tcc_add_crt(s, "crti.o"); - } - #endif - return 0; -diff --git a/tcc.c b/tcc.c -index cd887d1..1bb0c24 100644 ---- a/tcc.c -+++ b/tcc.c -@@ -1,6 +1,6 @@ - /* - * TCC - Tiny C Compiler -- * -+ * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or -@@ -162,6 +162,8 @@ static const char version[] = - " Darwin" - #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - " FreeBSD" -+#elif defined(__aero__) -+ " Aero" - #else - " Linux" - #endif -diff --git a/tcc.h b/tcc.h -index cd67973..e42f5fe 100644 ---- a/tcc.h -+++ b/tcc.h -@@ -162,6 +162,8 @@ extern long double strtold (const char *__nptr, char **__endptr); - # endif - #endif - -+#if 0 -+ - #if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT - # define CONFIG_TCC_BACKTRACE - # if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) \ -@@ -170,6 +172,8 @@ extern long double strtold (const char *__nptr, char **__endptr); - # endif - #endif - -+#endif -+ - /* ------------ path configuration ------------ */ - - #ifndef CONFIG_SYSROOT -diff --git a/tccelf.c b/tccelf.c -index 70d47e1..994ee59 100644 ---- a/tccelf.c -+++ b/tccelf.c -@@ -1202,8 +1202,10 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) - #endif - tcc_add_support(s1, TCC_LIBTCC1); - /* add crt end if not memory output */ -+ /* - if (s1->output_type != TCC_OUTPUT_MEMORY) - tcc_add_crt(s1, "crtn.o"); -+ */ - } - } - --- -2.25.1 - diff --git a/patches/wayland/wayland.patch b/patches/wayland/wayland.patch deleted file mode 100644 index d0986504bd6..00000000000 --- a/patches/wayland/wayland.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 845a4f951b9165576f6b930385bfef82b61394fc Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Thu, 26 May 2022 19:09:39 +1000 -Subject: [PATCH] wayland: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 2 ++ - src/wayland-os.c | 1 + - src/wayland-server.c | 2 ++ - tests/test-runner.c | 1 + - 4 files changed, 6 insertions(+) - -diff --git a/.gitignore b/.gitignore -index 4fefe5d..7013a49 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -6,3 +6,5 @@ - *~ - cscope.out - ctags -+ -+.vscode -\ No newline at end of file -diff --git a/src/wayland-os.c b/src/wayland-os.c -index 27c6035..43f7b00 100644 ---- a/src/wayland-os.c -+++ b/src/wayland-os.c -@@ -27,6 +27,7 @@ - - #include "../config.h" - -+#include - #include - #include - #include -diff --git a/src/wayland-server.c b/src/wayland-server.c -index 02f1365..d4cf79b 100644 ---- a/src/wayland-server.c -+++ b/src/wayland-server.c -@@ -1490,6 +1490,7 @@ wl_socket_lock(struct wl_socket *socket) - { - struct stat socket_stat; - -+ /* lockfiles are currently not supported on aero. - snprintf(socket->lock_addr, sizeof socket->lock_addr, - "%s%s", socket->addr.sun_path, LOCK_SUFFIX); - -@@ -1518,6 +1519,7 @@ wl_socket_lock(struct wl_socket *socket) - socket_stat.st_mode & S_IWGRP) { - unlink(socket->addr.sun_path); - } -+ */ - - return 0; - err_fd: -diff --git a/tests/test-runner.c b/tests/test-runner.c -index c0247b5..47280d1 100644 ---- a/tests/test-runner.c -+++ b/tests/test-runner.c -@@ -27,6 +27,7 @@ - #define _GNU_SOURCE - - #include -+#include - #include - #include - #include --- -2.25.1 - diff --git a/patches/xf86-input-keyboard/0001-keydev-aero-specific-changes.patch b/patches/xf86-input-keyboard/0001-keydev-aero-specific-changes.patch deleted file mode 100644 index 9ccd66e3662..00000000000 --- a/patches/xf86-input-keyboard/0001-keydev-aero-specific-changes.patch +++ /dev/null @@ -1,111 +0,0 @@ -From e61108c09c46a9b608c4c6f5e35ac666bf29c372 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Mon, 4 Jul 2022 11:45:06 +1000 -Subject: [PATCH] keydev: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 2 ++ - configure.ac | 5 +++++ - src/Makefile.am | 7 ++++++- - src/aero_kbd.c | 28 ++++++++++++++++++++++++++++ - 4 files changed, 41 insertions(+), 1 deletion(-) - create mode 100644 src/aero_kbd.c - -diff --git a/.gitignore b/.gitignore -index 5f04578..f10deba 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -76,3 +76,5 @@ core - # Edit the following section as needed - # For example, !report.pc overrides *.pc. See 'man gitignore' - # -+# editor configs: -+.vscode -diff --git a/configure.ac b/configure.ac -index c3ebdf3..33b36f9 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -69,6 +69,10 @@ case $host_os in - IS_SOLARIS="yes" - ;; - -+ aero*) -+ IS_AERO="yes" -+ ;; -+ - gnu*) - IS_HURD="yes" - ;; -@@ -95,6 +99,7 @@ case $host_os in - esac - AC_SUBST([OS_FLAGS]) - -+AM_CONDITIONAL(AERO, [test "x$IS_AERO" = xyes]) - AM_CONDITIONAL(LINUX, [test "x$IS_LINUX" = xyes]) - AM_CONDITIONAL(BSD, [test "x$IS_BSD" = xyes]) - AM_CONDITIONAL(SOLARIS, [test "x$IS_SOLARIS" = xyes]) -diff --git a/src/Makefile.am b/src/Makefile.am -index 8612c87..fac400e 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -26,11 +26,16 @@ kbd_drv_la_SOURCES = kbd.c xf86OSKbd.h xf86Keymap.h atKeynames.h - kbd_drv_la_LIBADD = $(XORG_LIBS) - kbd_drv_ladir = @inputdir@ - -+AERO_SRCS = aero_kbd.c at_scancode.c - BSD_SRCS = bsd_KbdMap.c bsd_kbd.c bsd_kbd.h at_scancode.c - HURD_SRCS = hurd_kbd.c at_scancode.c - LINUX_SRCS = lnx_KbdMap.c lnx_kbd.c lnx_kbd.h at_scancode.c - SOLARIS_SRCS = sun_kbd.c sun_kbd.h sun_kbdMap.c - -+if AERO -+kbd_drv_la_SOURCES += $(AERO_SRCS) -+endif -+ - if BSD - kbd_drv_la_SOURCES += $(BSD_SRCS) - endif -@@ -47,4 +52,4 @@ if HURD - kbd_drv_la_SOURCES += $(HURD_SRCS) - endif - --EXTRA_DIST = $(BSD_SRCS) $(HURD_SRCS) $(LINUX_SRCS) $(SOLARIS_SRCS) -+EXTRA_DIST = $(AERO_SRCS) $(BSD_SRCS) $(HURD_SRCS) $(LINUX_SRCS) $(SOLARIS_SRCS) -diff --git a/src/aero_kbd.c b/src/aero_kbd.c -new file mode 100644 -index 0000000..63fbc29 ---- /dev/null -+++ b/src/aero_kbd.c -@@ -0,0 +1,28 @@ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+ -+#include "compiler.h" -+ -+#include "xf86.h" -+#include "xf86Priv.h" -+#include "xf86_OSlib.h" -+ -+#include "atKeynames.h" -+#include "xf86Keymap.h" -+#include "xf86OSKbd.h" -+#include "xf86Xinput.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+Bool xf86OSKbdPreInit(InputInfoPtr pInfo) { -+ return FALSE; -+} --- -2.25.1 - diff --git a/patches/xf86-input-keyboard/jinx-working-patch.patch b/patches/xf86-input-keyboard/jinx-working-patch.patch new file mode 100644 index 00000000000..0a158a9547e --- /dev/null +++ b/patches/xf86-input-keyboard/jinx-working-patch.patch @@ -0,0 +1,164 @@ +diff --git xf86-input-keyboard-clean/configure.ac xf86-input-keyboard-workdir/configure.ac +index 0f71ce3..60616eb 100644 +--- xf86-input-keyboard-clean/configure.ac ++++ xf86-input-keyboard-workdir/configure.ac +@@ -69,6 +69,10 @@ case $host_os in + IS_SOLARIS="yes" + ;; + ++ aero*) ++ IS_AERO="yes" ++ ;; ++ + gnu*) + IS_HURD="yes" + ;; +@@ -98,6 +102,7 @@ AC_SUBST([OS_FLAGS]) + AM_CONDITIONAL(BSD, [test "x$IS_BSD" = xyes]) + AM_CONDITIONAL(SOLARIS, [test "x$IS_SOLARIS" = xyes]) + AM_CONDITIONAL(HURD, [test "x$IS_HURD" = xyes]) ++AM_CONDITIONAL(AERO, [test "x$IS_AERO" = xyes]) + + DRIVER_NAME=kbd + AC_SUBST([DRIVER_NAME]) +diff --git xf86-input-keyboard-clean/src/Makefile.am xf86-input-keyboard-workdir/src/Makefile.am +index 52f5f4d..19bf4cb 100644 +--- xf86-input-keyboard-clean/src/Makefile.am ++++ xf86-input-keyboard-workdir/src/Makefile.am +@@ -26,10 +26,15 @@ kbd_drv_la_SOURCES = kbd.c xf86OSKbd.h xf86Keymap.h atKeynames.h + kbd_drv_la_LIBADD = $(XORG_LIBS) + kbd_drv_ladir = @inputdir@ + ++AERO_SRCS = aero_kbd.c at_scancode.c + BSD_SRCS = bsd_KbdMap.c bsd_kbd.c bsd_kbd.h at_scancode.c + HURD_SRCS = hurd_kbd.c at_scancode.c + SOLARIS_SRCS = sun_kbd.c sun_kbd.h sun_kbdMap.c + ++if AERO ++kbd_drv_la_SOURCES += $(AERO_SRCS) ++endif ++ + if BSD + kbd_drv_la_SOURCES += $(BSD_SRCS) + endif +@@ -42,4 +47,4 @@ if HURD + kbd_drv_la_SOURCES += $(HURD_SRCS) + endif + +-EXTRA_DIST = $(BSD_SRCS) $(HURD_SRCS) $(SOLARIS_SRCS) ++EXTRA_DIST = $(AERO_SRCS) $(BSD_SRCS) $(HURD_SRCS) $(SOLARIS_SRCS) +diff --git xf86-input-keyboard-workdir/src/aero_kbd.c xf86-input-keyboard-workdir/src/aero_kbd.c +new file mode 100644 +index 0000000..c9cbc4e +--- /dev/null ++++ xf86-input-keyboard-workdir/src/aero_kbd.c +@@ -0,0 +1,109 @@ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++ ++#include "compiler.h" ++ ++#include "xf86.h" ++#include "xf86Priv.h" ++#include "xf86_OSlib.h" ++ ++#include "atKeynames.h" ++#include "xf86Keymap.h" ++#include "xf86OSKbd.h" ++#include "xf86Xinput.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int KbdOn(InputInfoPtr pInfo, int what) { ++ return Success; ++} ++ ++static int KbdOff(InputInfoPtr pInfo, int what) { ++ printf("aero::kbdOff: is a stub!\n"); ++ return -1; ++} ++ ++static void SoundKbdBell(InputInfoPtr pInfo, int loudness, int pitch, int duration) { ++ printf("aero::SoundKbdBell: is a stub!\n"); ++} ++ ++static void SetKbdLeds(InputInfoPtr pInfo, int leds) { printf("aero::SetKbdLeds: is a stub!\n"); } ++ ++static int GetKbdLeds(InputInfoPtr pInfo) { ++ printf("aero::GetKbdLeds: is a stub!\n"); ++ return -1; ++} ++ ++// Save the initial keyboard state. This function is called at the start ++// of each server generation. ++static int KbdInit(InputInfoPtr pInfo, int what) { ++ return Success; ++} ++ ++static void KbdGetMapping(InputInfoPtr pInfo, KeySymsPtr pKeySyms, CARD8 *pModMap) { ++ printf("aero::KbdGetMapping: is a stub!\n"); ++} ++ ++static void ReadInput(InputInfoPtr pInfo) { ++ KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; ++ ++ for(;;) { ++ uint8_t scancode; ++ size_t result = read(pInfo->fd, &scancode, sizeof(uint8_t)); ++ ++ if (result == sizeof(uint8_t)) { ++ pKbd->PostEvent(pInfo, scancode & 0x7f /* scancode */, scancode & 0x80 ? FALSE : TRUE /* released */); ++ } else { ++ return; ++ } ++ } ++} ++ ++static Bool OpenKeyboard(InputInfoPtr pInfo) { ++ char *kbdPath = xf86SetStrOption(pInfo->options, "Device", "/dev/kbd0"); ++ Bool ret; ++ ++ pInfo->fd = open(kbdPath, O_RDONLY | O_NONBLOCK); ++ ++ if (pInfo->fd == -1) { ++ xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, kbdPath); ++ ret = FALSE; ++ } else { ++ xf86MsgVerb(X_INFO, 3, "%s: opened device \"%s\"\n", pInfo->name, kbdPath); ++ pInfo->read_input = ReadInput; ++ ret = TRUE; ++ ++ // in case it wasn't set and we fell back to default. ++ xf86ReplaceStrOption(pInfo->options, "Device", kbdPath); ++ } ++ ++ free(kbdPath); ++ return ret; ++} ++ ++Bool xf86OSKbdPreInit(InputInfoPtr pInfo) { ++ KbdDevPtr pKbd = pInfo->private; ++ ++ pKbd->KbdInit = KbdInit; ++ pKbd->KbdOn = KbdOn; ++ pKbd->KbdOff = KbdOff; ++ pKbd->Bell = SoundKbdBell; ++ pKbd->SetLeds = SetKbdLeds; ++ pKbd->GetLeds = GetKbdLeds; ++ pKbd->KbdGetMapping = KbdGetMapping; ++ pKbd->OpenKeyboard = OpenKeyboard; ++ ++ pKbd->RemapScanCode = NULL; ++ pKbd->private = NULL; ++ ++ return TRUE; ++} diff --git a/patches/xf86-input-mouse/jinx-working-patch.patch b/patches/xf86-input-mouse/jinx-working-patch.patch new file mode 100644 index 00000000000..44e626272e1 --- /dev/null +++ b/patches/xf86-input-mouse/jinx-working-patch.patch @@ -0,0 +1,135 @@ +diff --git xf86-input-mouse-clean/configure.ac xf86-input-mouse-workdir/configure.ac +index 1d871b2..63361c7 100644 +--- xf86-input-mouse-clean/configure.ac ++++ xf86-input-mouse-workdir/configure.ac +@@ -84,6 +84,9 @@ case $host_os in + gnu*) + OS_MOUSE_NAME=hurd + ;; ++ aero*) ++ OS_MOUSE_NAME=aero ++ ;; + esac + AC_SUBST([OS_MOUSE_NAME]) + +diff --git xf86-input-mouse-workdir/src/aero_mouse.c xf86-input-mouse-workdir/src/aero_mouse.c +new file mode 100644 +index 0000000..5247c21 +--- /dev/null ++++ xf86-input-mouse-workdir/src/aero_mouse.c +@@ -0,0 +1,115 @@ ++#include "mouse.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xf86_OSlib.h" ++ ++#define MOUSE_FLAG_LB (1 << 0) ++#define MOUSE_FLAG_RB (1 << 1) ++#define MOUSE_FLAG_MB (1 << 2) ++ ++#define DEVPATH "/dev/mouse0" ++ ++struct mouse_packet { ++ int16_t x; ++ int16_t y; ++ ++ uint8_t flags; ++}; ++ ++static void MouseReadInput(InputInfoPtr pInfo) { ++ MouseDevPtr mouse = pInfo->private; ++ ++ struct mouse_packet packet; ++ ++ for (;;) { ++ size_t result = read(pInfo->fd, &packet, sizeof(struct mouse_packet)); ++ ++ if (result != sizeof(struct mouse_packet)) { ++ break; ++ } ++ ++ int b = mouse->lastButtons; ++ b &= ~0x7; ++ ++ b |= (packet.flags & MOUSE_FLAG_RB) ? 1 : 0; ++ b |= (packet.flags & MOUSE_FLAG_MB) ? 2 : 0; ++ b |= (packet.flags & MOUSE_FLAG_LB) ? 4 : 0; ++ ++ mouse->PostEvent(pInfo, b, packet.x, -packet.y, 0, 0); ++ } ++} ++ ++static Bool OsMousePreInit(InputInfoPtr pInfo, const char *protocol, int flags) { ++ MouseDevPtr mouse = pInfo->private; ++ mouse->protocol = protocol; ++ ++ xf86ProcessCommonOptions(pInfo, pInfo->options); ++ ++ pInfo->fd = xf86OpenSerial(pInfo->options); ++ if (pInfo->fd == -1) { ++ xf86Msg(X_ERROR, "%s: cannot open %s\n", pInfo->name, DEVPATH); ++ return FALSE; ++ } ++ ++ mouse->CommonOptions(pInfo); ++ pInfo->read_input = MouseReadInput; ++ return TRUE; ++} ++ ++static const char *internalNames[] = { ++ "Aero", ++ NULL ++}; ++ ++static const char ** BuiltinNames(void) { ++ return internalNames; ++} ++ ++static Bool CheckProtocol(const char *protocol) { ++ for (int i = 0; internalNames[i]; i++) { ++ if (xf86NameCmp(protocol, internalNames[i]) == 0) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static const char *FindDevice(InputInfoPtr pInfo, const char *protocol, int flags) { ++ struct stat st; ++ ++ if (stat(DEVPATH, &st) == -1) ++ return NULL; ++ ++ pInfo->options = xf86AddNewOption(pInfo->options, "Device", DEVPATH); ++ return DEVPATH; ++} ++ ++static const char *DefaultProtocol(void) { ++ return "Aero"; ++} ++ ++static int SupportedInterfaces(void) { ++ return MSE_PS2; ++} ++ ++OSMouseInfoPtr OSMouseInit(int flags) { ++ OSMouseInfoPtr p; ++ ++ p = calloc(sizeof(OSMouseInfoRec), 1); ++ if (p == NULL) ++ return NULL; ++ ++ p->SupportedInterfaces = SupportedInterfaces; ++ p->BuiltinNames = BuiltinNames; ++ p->FindDevice = FindDevice; ++ p->DefaultProtocol = DefaultProtocol; ++ p->CheckProtocol = CheckProtocol; ++ p->PreInit = OsMousePreInit; ++ ++ return p; ++} diff --git a/patches/xf86-video-fbdev/0001-fbdev-aero-specific-changes.patch b/patches/xf86-video-fbdev/jinx-working-patch.patch similarity index 54% rename from patches/xf86-video-fbdev/0001-fbdev-aero-specific-changes.patch rename to patches/xf86-video-fbdev/jinx-working-patch.patch index 8b91b6fd2f8..40f8d0a7575 100644 --- a/patches/xf86-video-fbdev/0001-fbdev-aero-specific-changes.patch +++ b/patches/xf86-video-fbdev/jinx-working-patch.patch @@ -1,43 +1,7 @@ -From 4a125d73f79cffc1edb41c4a9e9c0524bbc0abbd Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Sat, 2 Jul 2022 18:40:03 +1000 -Subject: [PATCH] fbdev: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 2 ++ - configure.ac | 8 +++++--- - src/Makefile.am | 2 +- - src/fbdev.c | 8 +++++--- - 4 files changed, 13 insertions(+), 7 deletions(-) - -diff --git a/.gitignore b/.gitignore -index 1c9de22..69be940 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -76,3 +76,5 @@ core - # Edit the following section as needed - # For example, !report.pc overrides *.pc. See 'man gitignore' - # -+# editor configs: -+.vscode -diff --git a/configure.ac b/configure.ac -index 27778cd..11f5e38 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -56,9 +56,9 @@ AC_ARG_ENABLE(pciaccess, AS_HELP_STRING([--enable-pciaccess], - [PCIACCESS=$enableval], [PCIACCESS=no]) - - # Store the list of server defined optional extensions in REQUIRED_MODULES --XORG_DRIVER_CHECK_EXT(RANDR, randrproto) --XORG_DRIVER_CHECK_EXT(RENDER, renderproto) --XORG_DRIVER_CHECK_EXT(XV, videoproto) -+# XORG_DRIVER_CHECK_EXT(RANDR, randrproto) -+# XORG_DRIVER_CHECK_EXT(RENDER, renderproto) -+# XORG_DRIVER_CHECK_EXT(XV, videoproto) - - # Obtain compiler/linker options for the driver dependencies - PKG_CHECK_MODULES(XORG, [xorg-server >= 1.0.99.901 xproto fontsproto $REQUIRED_MODULES]) +diff --git xf86-video-fbdev-clean/configure.ac xf86-video-fbdev-workdir/configure.ac +index 27778cd..67436db 100644 +--- xf86-video-fbdev-clean/configure.ac ++++ xf86-video-fbdev-workdir/configure.ac @@ -86,6 +86,8 @@ AC_SUBST([moduledir]) DRIVER_NAME=fbdev AC_SUBST([DRIVER_NAME]) @@ -47,23 +11,23 @@ index 27778cd..11f5e38 100644 AC_CONFIG_FILES([ Makefile src/Makefile -diff --git a/src/Makefile.am b/src/Makefile.am -index fbe420e..6e0779c 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am +diff --git xf86-video-fbdev-clean/src/Makefile.am xf86-video-fbdev-workdir/src/Makefile.am +index fbe420e..1ef5f49 100644 +--- xf86-video-fbdev-clean/src/Makefile.am ++++ xf86-video-fbdev-workdir/src/Makefile.am @@ -25,7 +25,7 @@ # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. AM_CFLAGS = @XORG_CFLAGS@ fbdev_drv_la_LTLIBRARIES = fbdev_drv.la -fbdev_drv_la_LDFLAGS = -module -avoid-version -+fbdev_drv_la_LDFLAGS = -module -avoid-version -R@moduledir@ -L@SYSROOT@@moduledir@ -lfb -lfbdevhw -lshadow ++fbdev_drv_la_LDFLAGS = -module -avoid-version -R@moduledir@ -L@SYSROOT@@moduledir@ -lfbdevhw -lshadow fbdev_drv_ladir = @moduledir@/drivers fbdev_drv_la_SOURCES = \ -diff --git a/src/fbdev.c b/src/fbdev.c +diff --git xf86-video-fbdev-clean/src/fbdev.c xf86-video-fbdev-workdir/src/fbdev.c index f25ef72..7facb9f 100644 ---- a/src/fbdev.c -+++ b/src/fbdev.c +--- xf86-video-fbdev-clean/src/fbdev.c ++++ xf86-video-fbdev-workdir/src/fbdev.c @@ -339,7 +339,7 @@ FBDevProbe(DriverPtr drv, int flags) dev = xf86FindOptionValue(devSections[i]->options,"fbdev"); @@ -106,7 +70,3 @@ index f25ef72..7facb9f 100644 +#ifdef XV { XF86VideoAdaptorPtr *ptr; - --- -2.25.1 - diff --git a/patches/xfe/jinx-working-patch.patch b/patches/xfe/jinx-working-patch.patch new file mode 100644 index 00000000000..a9b187463eb --- /dev/null +++ b/patches/xfe/jinx-working-patch.patch @@ -0,0 +1,124 @@ +diff --git xfe-clean/configure.ac xfe-workdir/configure.ac +index 0fa6dc9..ecaa037 100644 +--- xfe-clean/configure.ac ++++ xfe-workdir/configure.ac +@@ -69,9 +69,9 @@ AC_FUNC_GETGROUPS + AC_FUNC_GETMNTENT + AC_FUNC_LSTAT + AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK +-AC_FUNC_MALLOC ++#AC_FUNC_MALLOC + AC_FUNC_MKTIME +-AC_FUNC_REALLOC ++#AC_FUNC_REALLOC + AC_FUNC_STAT + AC_FUNC_UTIME_NULL + AC_CHECK_FUNCS([endgrent endpwent gethostname getmntent gettimeofday lchown memset mkdir mkfifo putenv rmdir setlocale sqrt strchr strdup strerror strstr strtol strtoul strtoull utime]) +@@ -87,25 +87,19 @@ AC_CHECK_LIB(FOX-1.6,fxfindfox,,AC_MSG_ERROR("libFOX-1.6 not found")) + + # Check for FOX 1.6 header files + AC_LANG([C++]) +-AC_CHECK_HEADER(fox-1.6/fx.h,,AC_MSG_ERROR("fox-1.6/fx.h not found")) ++#AC_CHECK_HEADER(fox-1.6/fx.h,,AC_MSG_ERROR("fox-1.6/fx.h not found")) + + +-# Check if fox-config exists +-AC_CHECK_PROGS(FOX_CONFIG,fox-config-1.6 fox-1.6-config fox-config) +-if test no"$FOX_CONFIG" = no ; then +- AC_MSG_ERROR("fox-config not found") +-fi +- + + # Include flags for the FOX library +-FOXCFLAGS=`$FOX_CONFIG --cflags` ++FOXCFLAGS=`$PKG_CONFIG --cflags fox` + CXXFLAGS="${CXXFLAGS} $FOXCFLAGS" + + + # Check if FOX was compiled with xft support +-TEST_XFT=`$FOX_CONFIG --libs | grep Xft` ++TEST_XFT=yes + if test "x$TEST_XFT" != "x" ; then +- ++ + echo "checking whether FOX was compiled with Xft support... yes" + + # Check for FreeType2 +@@ -135,7 +129,7 @@ if test "x$TEST_XFT" != "x" ; then + CXXFLAGS="$CXXFLAGS -DHAVE_XFT_H" + ], AC_MSG_ERROR("Xft not found")) + fi +- AC_CHECK_HEADER(X11/Xft/Xft.h,,AC_MSG_ERROR("Xft.h not found")) ++ #AC_CHECK_HEADER(X11/Xft/Xft.h,,AC_MSG_ERROR("Xft.h not found")) + + else + echo "checking whether FOX was compiled with Xft support... no" +@@ -149,28 +143,28 @@ else + echo " sudo make install" + echo "=============================================================================================" + echo "" +- AC_MSG_ERROR("missing Xft support in FOX") ++ AC_MSG_ERROR("missing Xft support in FOX") + fi + + + # Check for Xlib headers +-AC_CHECK_HEADER(X11/Xlib.h,,AC_MSG_ERROR("Xlib.h not found")) ++#AC_CHECK_HEADER(X11/Xlib.h,,AC_MSG_ERROR("Xlib.h not found")) + + # Check for XRandR support + AC_MSG_CHECKING(for xrandr extension) + AC_ARG_WITH(xrandr,[ --with-xrandr compile with XRandR support]) + AC_MSG_RESULT([$with_xrandr]) +-if test "x$with_xrandr" != "xno"; then +-AC_CHECK_HEADERS(X11/extensions/Xrandr.h,CXXFLAGS="${CXXFLAGS} -DHAVE_XRANDR_H=1"; LIBS="${LIBS} -lXrandr") +-fi ++#if test "x$with_xrandr" != "xno"; then ++#AC_CHECK_HEADERS(X11/extensions/Xrandr.h,CXXFLAGS="${CXXFLAGS} -DHAVE_XRANDR_H=1"; LIBS="${LIBS} -lXrandr") ++#fi + + # Check for libPNG + AC_CHECK_LIB(png, png_read_info,,AC_MSG_ERROR("libPNG not found")) +-AC_CHECK_HEADER(png.h,,AC_MSG_ERROR("png.h not found")) ++#AC_CHECK_HEADER(png.h,,AC_MSG_ERROR("png.h not found")) + + # Check for fontconfig + AC_CHECK_LIB(fontconfig, FcInit,, AC_MSG_ERROR("fontconfig not found")) +-AC_CHECK_HEADER(fontconfig/fontconfig.h,,AC_MSG_ERROR("fontconfig.h not found")) ++#AC_CHECK_HEADER(fontconfig/fontconfig.h,,AC_MSG_ERROR("fontconfig.h not found")) + + # Check for startup notification support + AC_MSG_CHECKING(for startup notification) +diff --git xfe-clean/src/ArchInputDialog.cpp xfe-workdir/src/ArchInputDialog.cpp +index f0314bb..4b6e170 100644 +--- xfe-clean/src/ArchInputDialog.cpp ++++ xfe-workdir/src/ArchInputDialog.cpp +@@ -1,5 +1,6 @@ + // Input dialog for the add to archive command + ++#include + #include "config.h" + #include "i18n.h" + +diff --git xfe-clean/src/Bookmarks.cpp xfe-workdir/src/Bookmarks.cpp +index 241ef32..113c503 100644 +--- xfe-clean/src/Bookmarks.cpp ++++ xfe-workdir/src/Bookmarks.cpp +@@ -1,5 +1,6 @@ + // Bookmarks list. Taken from the FOX library (FXRecentFiles) and slightly modified. + ++#include + #include "config.h" + #include "i18n.h" + +diff --git xfe-clean/src/BrowseInputDialog.cpp xfe-workdir/src/BrowseInputDialog.cpp +index 4c64e68..ff0c1ad 100644 +--- xfe-clean/src/BrowseInputDialog.cpp ++++ xfe-workdir/src/BrowseInputDialog.cpp +@@ -1,5 +1,6 @@ + // Input dialog with file browse icon + ++#include + #include "config.h" + #include "i18n.h" + diff --git a/patches/xorg-proto/0001-xorg-proto-aero-specific-changes.patch b/patches/xorg-proto/0001-xorg-proto-aero-specific-changes.patch deleted file mode 100644 index 853f1a8f78f..00000000000 --- a/patches/xorg-proto/0001-xorg-proto-aero-specific-changes.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 30656370d8418d469ed311fad84412d12fe0028e Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Tue, 28 Jun 2022 17:04:52 +1000 -Subject: [PATCH] xorg::proto: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 3 +++ - include/X11/Xos.h | 2 +- - include/X11/Xos_r.h | 2 +- - 3 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/.gitignore b/.gitignore -index 1baa360..dc18465 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -18,3 +18,6 @@ man/Xprint.7 - missing - stamp-h1 - stamp-h2 -+ -+# editor configs: -+.vscode -diff --git a/include/X11/Xos.h b/include/X11/Xos.h -index 28dfc67..1c4092e 100644 ---- a/include/X11/Xos.h -+++ b/include/X11/Xos.h -@@ -60,7 +60,7 @@ in this Software without prior written authorization from The Open Group. - */ - - # include --# if defined(__SCO__) || defined(__UNIXWARE__) || defined(__sun) || defined(__CYGWIN__) || defined(_AIX) || defined(__APPLE__) -+# if defined(__SCO__) || defined(__UNIXWARE__) || defined(__sun) || defined(__CYGWIN__) || defined(_AIX) || defined(__APPLE__) || defined(__aero__) - # include - # else - # ifndef index -diff --git a/include/X11/Xos_r.h b/include/X11/Xos_r.h -index f963b64..19ef5f4 100644 ---- a/include/X11/Xos_r.h -+++ b/include/X11/Xos_r.h -@@ -318,7 +318,7 @@ static __inline__ void _Xpw_copyPasswd(_Xgetpwparams p) - (_Xos_processUnlock), \ - (p).pwp ) - --#elif !defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(__APPLE__) -+#elif !defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(__APPLE__) && !defined(__aero__) - # define X_NEEDS_PWPARAMS - typedef struct { - struct passwd pws; --- -2.25.1 - diff --git a/patches/xorg-proto/jinx-working-patch.patch b/patches/xorg-proto/jinx-working-patch.patch new file mode 100644 index 00000000000..ddea30d9e82 --- /dev/null +++ b/patches/xorg-proto/jinx-working-patch.patch @@ -0,0 +1,40 @@ +diff --git xorg-proto-clean/include/X11/Xfuncs.h xorg-proto-workdir/include/X11/Xfuncs.h +index b23c283..89dbbb5 100644 +--- xorg-proto-clean/include/X11/Xfuncs.h ++++ xorg-proto-workdir/include/X11/Xfuncs.h +@@ -44,7 +44,7 @@ void bcopy(); + # define bcmp(b1,b2,len) memcmp(b1, b2, len) + # else + # include +-# if defined(__SCO__) || defined(__sun) || defined(__UNIXWARE__) || defined(__CYGWIN__) || defined(_AIX) || defined(__APPLE__) ++# if defined(__SCO__) || defined(__sun) || defined(__UNIXWARE__) || defined(__CYGWIN__) || defined(_AIX) || defined(__APPLE__) || defined(__aero__) + # include + # endif + # define _XFUNCS_H_INCLUDED_STRING_H +diff --git xorg-proto-clean/include/X11/Xos.h xorg-proto-workdir/include/X11/Xos.h +index 75cc5b7..6c46e33 100644 +--- xorg-proto-clean/include/X11/Xos.h ++++ xorg-proto-workdir/include/X11/Xos.h +@@ -60,7 +60,7 @@ in this Software without prior written authorization from The Open Group. + */ + + # include +-# if defined(__SCO__) || defined(__UNIXWARE__) || defined(__sun) || defined(__CYGWIN__) || defined(_AIX) || defined(__APPLE__) || defined(__FreeBSD__) ++# if defined(__SCO__) || defined(__UNIXWARE__) || defined(__sun) || defined(__CYGWIN__) || defined(_AIX) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__aero__) + # include + # else + # ifndef index +diff --git xorg-proto-clean/include/X11/Xos_r.h xorg-proto-workdir/include/X11/Xos_r.h +index f963b64..542c19d 100644 +--- xorg-proto-clean/include/X11/Xos_r.h ++++ xorg-proto-workdir/include/X11/Xos_r.h +@@ -318,7 +318,7 @@ static __inline__ void _Xpw_copyPasswd(_Xgetpwparams p) + (_Xos_processUnlock), \ + (p).pwp ) + +-#elif !defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(__APPLE__) ++#elif !defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(__APPLE__) && !defined(__aero__) + # define X_NEEDS_PWPARAMS + typedef struct { + struct passwd pws; + diff --git a/patches/xorg-server/0001-xserver-aero-specific-changes.patch b/patches/xorg-server/0001-xserver-aero-specific-changes.patch deleted file mode 100644 index c9890ecc64a..00000000000 --- a/patches/xorg-server/0001-xserver-aero-specific-changes.patch +++ /dev/null @@ -1,382 +0,0 @@ -From 6a1cb57184179a2971bedd477fa71f30bbac6a09 Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Thu, 30 Jun 2022 11:10:21 +1000 -Subject: [PATCH] xserver: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - .gitignore | 2 ++ - configure.ac | 2 ++ - hw/xfree86/common/xf86Bus.c | 2 ++ - hw/xfree86/common/xf86Config.c | 2 ++ - hw/xfree86/common/xf86Configure.c | 1 + - hw/xfree86/common/xf86Events.c | 1 + - hw/xfree86/common/xf86Helper.c | 1 + - hw/xfree86/common/xf86Init.c | 2 ++ - hw/xfree86/fbdevhw/fbdevhw.c | 36 +++++++++++++++--------- - hw/xfree86/fbdevhw/fbdevhw.h | 4 +-- - hw/xfree86/os-support/shared/posix_tty.c | 3 ++ - hw/xfree86/os-support/shared/sigio.c | 3 ++ - include/os.h | 1 + - mi/mibitblt.c | 2 ++ - os/access.c | 2 +- - os/ospoll.c | 2 ++ - os/utils.c | 6 ++-- - 17 files changed, 52 insertions(+), 20 deletions(-) - -diff --git a/.gitignore b/.gitignore -index dc56b46..81d9886 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -80,3 +80,5 @@ core - doltcompile - doltlibtool - xserver.ent -+# editor configs: -+.vscode -diff --git a/configure.ac b/configure.ac -index 0909cc5..080b906 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1967,6 +1967,8 @@ if test "x$XORG" = xyes; then - XORG_DRIVER_MODESETTING=yes - fi - -+ XORG_DRIVER_MODESETTING=no -+ - AC_SUBST([XORG_LIBS]) - AC_SUBST([XORG_SYS_LIBS]) - AC_SUBST([XORG_INCS]) -diff --git a/hw/xfree86/common/xf86Bus.c b/hw/xfree86/common/xf86Bus.c -index a8f1073..d7399aa 100644 ---- a/hw/xfree86/common/xf86Bus.c -+++ b/hw/xfree86/common/xf86Bus.c -@@ -536,6 +536,7 @@ xf86GetDevFromEntity(int entityIndex, int instance) - void - xf86PostProbe(void) - { -+#if 0 - if (fbSlotClaimed && ( - #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) - sbusSlotClaimed || -@@ -551,6 +552,7 @@ xf86PostProbe(void) - )) - FatalError("Cannot run in framebuffer mode. Please specify busIDs " - " for all framebuffer devices\n"); -+#endif - } - - int -diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c -index 09d27ec..83be062 100644 ---- a/hw/xfree86/common/xf86Config.c -+++ b/hw/xfree86/common/xf86Config.c -@@ -49,6 +49,8 @@ - #include - #include - -+#include -+ - #include "xf86.h" - #include "xf86Modes.h" - #include "xf86Parser.h" -diff --git a/hw/xfree86/common/xf86Configure.c b/hw/xfree86/common/xf86Configure.c -index 44e7591..6265f65 100644 ---- a/hw/xfree86/common/xf86Configure.c -+++ b/hw/xfree86/common/xf86Configure.c -@@ -27,6 +27,7 @@ - #include - #endif - -+#include - #include "xf86.h" - #include "xf86Config.h" - #include "xf86_OSlib.h" -diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c -index 8a800bd..d847fa8 100644 ---- a/hw/xfree86/common/xf86Events.c -+++ b/hw/xfree86/common/xf86Events.c -@@ -53,6 +53,7 @@ - #include - #endif - -+#include - #include - #include - #include -diff --git a/hw/xfree86/common/xf86Helper.c b/hw/xfree86/common/xf86Helper.c -index 42a51dd..813bad1 100644 ---- a/hw/xfree86/common/xf86Helper.c -+++ b/hw/xfree86/common/xf86Helper.c -@@ -38,6 +38,7 @@ - #include - #endif - -+#include - #include - #include "os.h" - #include "servermd.h" -diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c -index 2ec6b2f..c1d9c24 100644 ---- a/hw/xfree86/common/xf86Init.c -+++ b/hw/xfree86/common/xf86Init.c -@@ -37,6 +37,8 @@ - #include - #include - -+#include -+ - #undef HAS_UTSNAME - #if !defined(WIN32) - #define HAS_UTSNAME 1 -diff --git a/hw/xfree86/fbdevhw/fbdevhw.c b/hw/xfree86/fbdevhw/fbdevhw.c -index 9508951..a4c1e6e 100644 ---- a/hw/xfree86/fbdevhw/fbdevhw.c -+++ b/hw/xfree86/fbdevhw/fbdevhw.c -@@ -10,12 +10,13 @@ - #include "xf86_OSproc.h" - - /* pci stuff */ --#include "xf86Pci.h" -+// #include "xf86Pci.h" - - #include "xf86cmap.h" - - #include "fbdevhw.h" --#include "fbpriv.h" -+// #include "fbpriv.h" -+#include - #include "globals.h" - #include - -@@ -259,6 +260,7 @@ fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode) - /** - * Try to find the framebuffer device for a given PCI device - */ -+#if 0 - static int - fbdev_open_pci(struct pci_device *pPci, char **namep) - { -@@ -303,6 +305,7 @@ fbdev_open_pci(struct pci_device *pPci, char **namep) - xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n"); - return -1; - } -+#endif - - static int - fbdev_open(int scrnIndex, const char *dev, char **namep) -@@ -330,6 +333,7 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) - } - - /* only touch non-PCI devices on this path */ -+#if 0 - { - char buf[PATH_MAX]; - char *sysfs_path = NULL; -@@ -344,6 +348,7 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) - } - free(sysfs_path); - } -+#endif - - if (namep) { - if (-1 == ioctl(fd, FBIOGET_FSCREENINFO, (void *) (&fix))) { -@@ -363,14 +368,16 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) - /* -------------------------------------------------------------------- */ - - Bool --fbdevHWProbe(struct pci_device *pPci, char *device, char **namep) -+fbdevHWProbe(void *pPci, char *device, char **namep) - { - int fd; - -- if (pPci) -- fd = fbdev_open_pci(pPci, namep); -- else -- fd = fbdev_open(-1, device, namep); -+ // if (pPci) -+ // fd = fbdev_open_pci(pPci, namep); -+ // else -+ // fd = fbdev_open(-1, device, namep); -+ -+ fd = fbdev_open(-1, device, namep); - - if (-1 == fd) - return FALSE; -@@ -379,7 +386,7 @@ fbdevHWProbe(struct pci_device *pPci, char *device, char **namep) - } - - Bool --fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device) -+fbdevHWInit(ScrnInfoPtr pScrn, void *pPci, char *device) - { - fbdevHWPtr fPtr; - -@@ -387,10 +394,11 @@ fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device) - fPtr = FBDEVHWPTR(pScrn); - - /* open device */ -- if (pPci) -- fPtr->fd = fbdev_open_pci(pPci, NULL); -- else -- fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL); -+ // if (pPci) -+ // fPtr->fd = fbdev_open_pci(pPci, NULL); -+ // else -+ // fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL); -+ fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL); - if (-1 == fPtr->fd) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to open framebuffer device, consult warnings" -@@ -881,7 +889,7 @@ RETRY: - "FBIOBLANK: %s\n", strerror(errno)); - break; - case EINTR: -- case ERESTART: -+ // case ERESTART: - goto RETRY; - default: - fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED); -@@ -915,7 +923,7 @@ RETRY: - "FBIOBLANK: %s\n", strerror(errno)); - break; - case EINTR: -- case ERESTART: -+ // case ERESTART: - goto RETRY; - default: - fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED); -diff --git a/hw/xfree86/fbdevhw/fbdevhw.h b/hw/xfree86/fbdevhw/fbdevhw.h -index 4984ccf..bb3e2f8 100644 ---- a/hw/xfree86/fbdevhw/fbdevhw.h -+++ b/hw/xfree86/fbdevhw/fbdevhw.h -@@ -16,9 +16,9 @@ extern _X_EXPORT void fbdevHWFreeRec(ScrnInfoPtr pScrn); - - extern _X_EXPORT int fbdevHWGetFD(ScrnInfoPtr pScrn); - --extern _X_EXPORT Bool fbdevHWProbe(struct pci_device *pPci, char *device, -+extern _X_EXPORT Bool fbdevHWProbe(void *pPci, char *device, - char **namep); --extern _X_EXPORT Bool fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, -+extern _X_EXPORT Bool fbdevHWInit(ScrnInfoPtr pScrn, void *pPci, - char *device); - - extern _X_EXPORT char *fbdevHWGetName(ScrnInfoPtr pScrn); -diff --git a/hw/xfree86/os-support/shared/posix_tty.c b/hw/xfree86/os-support/shared/posix_tty.c -index 0cb9788..e8cac5d 100644 ---- a/hw/xfree86/os-support/shared/posix_tty.c -+++ b/hw/xfree86/os-support/shared/posix_tty.c -@@ -56,6 +56,9 @@ - #include - #endif - -+#include -+#include -+ - #include - #include - #include "xf86.h" -diff --git a/hw/xfree86/os-support/shared/sigio.c b/hw/xfree86/os-support/shared/sigio.c -index 247bec7..216e8cd 100644 ---- a/hw/xfree86/os-support/shared/sigio.c -+++ b/hw/xfree86/os-support/shared/sigio.c -@@ -56,6 +56,9 @@ - #include - #endif - -+#include -+#include -+ - #include - #include - #include "xf86.h" -diff --git a/include/os.h b/include/os.h -index 2a1c29e..2a7fc76 100644 ---- a/include/os.h -+++ b/include/os.h -@@ -51,6 +51,7 @@ SOFTWARE. - #include - #include - #include -+#include - #ifdef MONOTONIC_CLOCK - #include - #endif -diff --git a/mi/mibitblt.c b/mi/mibitblt.c -index 43d9bd9..740c0d2 100644 ---- a/mi/mibitblt.c -+++ b/mi/mibitblt.c -@@ -49,6 +49,8 @@ SOFTWARE. - #include - #endif - -+#include -+ - #include - #include - -diff --git a/os/access.c b/os/access.c -index 9724616..81befe3 100644 ---- a/os/access.c -+++ b/os/access.c -@@ -117,7 +117,7 @@ SOFTWARE. - #endif - #endif - --#if defined(SVR4) || (defined(SYSV) && defined(__i386__)) || defined(__GNU__) -+#if defined(SVR4) || (defined(SYSV) && defined(__i386__)) || defined(__GNU__) || defined(__aero__) - #include - #endif - #if defined(SYSV) && defined(__i386__) -diff --git a/os/ospoll.c b/os/ospoll.c -index c68aabc..19006c3 100644 ---- a/os/ospoll.c -+++ b/os/ospoll.c -@@ -45,11 +45,13 @@ - #define HAVE_OSPOLL 1 - #endif - -+#if 0 - #if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1) - #include - #define EPOLL 1 - #define HAVE_OSPOLL 1 - #endif -+#endif - - #if !HAVE_OSPOLL - #include "xserver_poll.h" -diff --git a/os/utils.c b/os/utils.c -index 2ba1c80..ffa961f 100644 ---- a/os/utils.c -+++ b/os/utils.c -@@ -1402,7 +1402,7 @@ System(const char *command) - return -1; - } - -- return p == -1 ? -1 : status; -+ return p == -1 ? -1 : !WIFEXITED(status) || WEXITSTATUS(status); - } - - static struct pid { -@@ -1474,7 +1474,7 @@ Popen(const char *command, const char *type) - } - close(pdes[1]); - } -- execl("/bin/sh", "sh", "-c", command, (char *) NULL); -+ execl("/usr/bin/bash", "sh", "-c", command, (char *) NULL); - _exit(127); - } - -@@ -1632,7 +1632,7 @@ Pclose(void *iop) - } - #endif - -- return pid == -1 ? -1 : pstat; -+ return pid == -1 ? -1 : !WIFEXITED(pstat) || WEXITSTATUS(pstat); - } - - int --- -2.25.1 - diff --git a/patches/xorg-server/jinx-working-patch.patch b/patches/xorg-server/jinx-working-patch.patch new file mode 100644 index 00000000000..11667724116 --- /dev/null +++ b/patches/xorg-server/jinx-working-patch.patch @@ -0,0 +1,363 @@ +diff --git xorg-server-clean/configure.ac xorg-server-workdir/configure.ac +index fad7b57..ed4445c 100644 +--- xorg-server-clean/configure.ac ++++ xorg-server-workdir/configure.ac +@@ -1341,7 +1341,7 @@ AM_CONDITIONAL(INT10MODULE, test "x$INT10MODULE" = xyes) + AC_DEFINE(SHAPE, 1, [Support SHAPE extension]) + + if test "x$XKBPATH" = "xauto"; then +- XKBPATH=$(pkg-config --variable datadir xkbcomp || echo ${datadir})/X11/xkb ++ XKBPATH=$($PKG_CONFIG --variable datadir xkbcomp || echo ${datadir})/X11/xkb + fi + + AC_DEFINE_DIR(XKB_BASE_DIRECTORY, XKBPATH, [Path to XKB data]) +@@ -1351,7 +1351,7 @@ AC_ARG_WITH(xkb-bin-directory, + [XKB_BIN_DIRECTORY="auto"]) + + if test "x$XKB_BIN_DIRECTORY" = "xauto"; then +- XKB_BIN_DIRECTORY=$(pkg-config --variable bindir xkbcomp) ++ XKB_BIN_DIRECTORY=$($PKG_CONFIG --variable bindir xkbcomp) + if test -z $XKB_BIN_DIRECTORY; then + XKB_BIN_DIRECTORY="$bindir" + fi +@@ -1946,6 +1946,8 @@ if test "x$XORG" = xyes; then + if test "x$DRM" = xyes -a "x$DRI2" = xyes; then + XORG_DRIVER_MODESETTING=yes + fi ++ ++ XORG_DRIVER_MODESETTING=no + + AC_SUBST([XORG_LIBS]) + AC_SUBST([XORG_SYS_LIBS]) +@@ -2127,7 +2129,7 @@ dnl XWin requires OpenGL spec files in order to generate wrapper code for native + AC_MSG_RESULT(yes) + if test "x$KHRONOS_SPEC_DIR" = "xauto" ; then + PKG_CHECK_MODULES([KHRONOS_OPENGL_REGISTRY], [khronos-opengl-registry]) +- KHRONOS_SPEC_DIR=`pkg-config khronos-opengl-registry --variable=specdir` ++ KHRONOS_SPEC_DIR=`$PKG_CONFIG khronos-opengl-registry --variable=specdir` + fi + AC_SUBST(KHRONOS_SPEC_DIR) + fi +diff --git xorg-server-clean/hw/xfree86/common/xf86Bus.c xorg-server-workdir/hw/xfree86/common/xf86Bus.c +index fd144db..6eb018c 100644 +--- xorg-server-clean/hw/xfree86/common/xf86Bus.c ++++ xorg-server-workdir/hw/xfree86/common/xf86Bus.c +@@ -556,6 +556,7 @@ xf86GetDevFromEntity(int entityIndex, int instance) + void + xf86PostProbe(void) + { ++/* + if (fbSlotClaimed && ( + #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__) + sbusSlotClaimed || +@@ -571,6 +572,7 @@ xf86PostProbe(void) + )) + FatalError("Cannot run in framebuffer mode. Please specify busIDs " + " for all framebuffer devices\n"); ++*/ + } + + Bool +diff --git xorg-server-clean/hw/xfree86/common/xf86Config.c xorg-server-workdir/hw/xfree86/common/xf86Config.c +index 5d814c1..14ebfe6 100644 +--- xorg-server-clean/hw/xfree86/common/xf86Config.c ++++ xorg-server-workdir/hw/xfree86/common/xf86Config.c +@@ -49,6 +49,8 @@ + #include + #include + ++#include ++ + #include "xf86.h" + #include "xf86Modes.h" + #include "xf86Parser.h" +diff --git xorg-server-clean/hw/xfree86/common/xf86Configure.c xorg-server-workdir/hw/xfree86/common/xf86Configure.c +index 4347f6d..52594c6 100644 +--- xorg-server-clean/hw/xfree86/common/xf86Configure.c ++++ xorg-server-workdir/hw/xfree86/common/xf86Configure.c +@@ -27,6 +27,8 @@ + #include + #endif + ++#include ++ + #include "xf86.h" + #include "xf86Config.h" + #include "xf86_OSlib.h" +diff --git xorg-server-clean/hw/xfree86/common/xf86Events.c xorg-server-workdir/hw/xfree86/common/xf86Events.c +index 395bbc7..4bf86cb 100644 +--- xorg-server-clean/hw/xfree86/common/xf86Events.c ++++ xorg-server-workdir/hw/xfree86/common/xf86Events.c +@@ -53,6 +53,8 @@ + #include + #endif + ++#include ++ + #include + #include + #include +diff --git xorg-server-clean/hw/xfree86/common/xf86Helper.c xorg-server-workdir/hw/xfree86/common/xf86Helper.c +index 0389945..b53b1a7 100644 +--- xorg-server-clean/hw/xfree86/common/xf86Helper.c ++++ xorg-server-workdir/hw/xfree86/common/xf86Helper.c +@@ -38,6 +38,8 @@ + #include + #endif + ++#include ++ + #include + #include "mi.h" + #include "os.h" +diff --git xorg-server-clean/hw/xfree86/common/xf86Init.c xorg-server-workdir/hw/xfree86/common/xf86Init.c +index 5695e71..96c2d15 100644 +--- xorg-server-clean/hw/xfree86/common/xf86Init.c ++++ xorg-server-workdir/hw/xfree86/common/xf86Init.c +@@ -37,6 +37,8 @@ + #include + #include + ++#include ++ + #undef HAS_UTSNAME + #if !defined(WIN32) + #define HAS_UTSNAME 1 +diff --git xorg-server-clean/hw/xfree86/fbdevhw/fbdevhw.c xorg-server-workdir/hw/xfree86/fbdevhw/fbdevhw.c +index 3d8b92e..f7be685 100644 +--- xorg-server-clean/hw/xfree86/fbdevhw/fbdevhw.c ++++ xorg-server-workdir/hw/xfree86/fbdevhw/fbdevhw.c +@@ -10,12 +10,12 @@ + #include "xf86_OSproc.h" + + /* pci stuff */ +-#include "xf86Pci.h" ++//#include "xf86Pci.h" + + #include "xf86cmap.h" + + #include "fbdevhw.h" +-#include "fbpriv.h" ++#include + #include "globals.h" + #include + +@@ -259,6 +259,7 @@ fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode) + /** + * Try to find the framebuffer device for a given PCI device + */ ++/* + static int + fbdev_open_pci(struct pci_device *pPci, char **namep) + { +@@ -303,6 +304,7 @@ fbdev_open_pci(struct pci_device *pPci, char **namep) + xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n"); + return -1; + } ++*/ + + static int + fbdev_open(int scrnIndex, const char *dev, char **namep) +@@ -330,6 +332,7 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) + } + + /* only touch non-PCI devices on this path */ ++/* + { + char buf[PATH_MAX] = {0}; + char *sysfs_path = NULL; +@@ -344,6 +347,7 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) + } + free(sysfs_path); + } ++*/ + + if (namep) { + if (-1 == ioctl(fd, FBIOGET_FSCREENINFO, (void *) (&fix))) { +@@ -363,14 +367,11 @@ fbdev_open(int scrnIndex, const char *dev, char **namep) + /* -------------------------------------------------------------------- */ + + Bool +-fbdevHWProbe(struct pci_device *pPci, char *device, char **namep) ++fbdevHWProbe(void *pPci, char *device, char **namep) + { + int fd; + +- if (pPci) +- fd = fbdev_open_pci(pPci, namep); +- else +- fd = fbdev_open(-1, device, namep); ++ fd = fbdev_open(-1, device, namep); + + if (-1 == fd) + return FALSE; +@@ -379,7 +380,7 @@ fbdevHWProbe(struct pci_device *pPci, char *device, char **namep) + } + + Bool +-fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device) ++fbdevHWInit(ScrnInfoPtr pScrn, void *pPci, char *device) + { + fbdevHWPtr fPtr; + +@@ -387,10 +388,7 @@ fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device) + fPtr = FBDEVHWPTR(pScrn); + + /* open device */ +- if (pPci) +- fPtr->fd = fbdev_open_pci(pPci, NULL); +- else +- fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL); ++ fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL); + if (-1 == fPtr->fd) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to open framebuffer device, consult warnings" +@@ -881,7 +879,7 @@ RETRY: + "FBIOBLANK: %s\n", strerror(errno)); + break; + case EINTR: +- case ERESTART: ++ // case ERESTART: + goto RETRY; + default: + fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED); +@@ -915,7 +913,7 @@ RETRY: + "FBIOBLANK: %s\n", strerror(errno)); + break; + case EINTR: +- case ERESTART: ++ // case ERESTART: + goto RETRY; + default: + fPtr->unsupported_ioctls |= (1 << FBIOBLANK_UNSUPPORTED); +diff --git xorg-server-clean/hw/xfree86/fbdevhw/fbdevhw.h xorg-server-workdir/hw/xfree86/fbdevhw/fbdevhw.h +index 4984ccf..bb3e2f8 100644 +--- xorg-server-clean/hw/xfree86/fbdevhw/fbdevhw.h ++++ xorg-server-workdir/hw/xfree86/fbdevhw/fbdevhw.h +@@ -16,9 +16,9 @@ extern _X_EXPORT void fbdevHWFreeRec(ScrnInfoPtr pScrn); + + extern _X_EXPORT int fbdevHWGetFD(ScrnInfoPtr pScrn); + +-extern _X_EXPORT Bool fbdevHWProbe(struct pci_device *pPci, char *device, ++extern _X_EXPORT Bool fbdevHWProbe(void *pPci, char *device, + char **namep); +-extern _X_EXPORT Bool fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, ++extern _X_EXPORT Bool fbdevHWInit(ScrnInfoPtr pScrn, void *pPci, + char *device); + + extern _X_EXPORT char *fbdevHWGetName(ScrnInfoPtr pScrn); +diff --git xorg-server-clean/hw/xfree86/os-support/shared/posix_tty.c xorg-server-workdir/hw/xfree86/os-support/shared/posix_tty.c +index 0cb9788..e8cac5d 100644 +--- xorg-server-clean/hw/xfree86/os-support/shared/posix_tty.c ++++ xorg-server-workdir/hw/xfree86/os-support/shared/posix_tty.c +@@ -56,6 +56,9 @@ + #include + #endif + ++#include ++#include ++ + #include + #include + #include "xf86.h" +diff --git xorg-server-clean/hw/xfree86/os-support/shared/sigio.c xorg-server-workdir/hw/xfree86/os-support/shared/sigio.c +index ad8af60..6f81278 100644 +--- xorg-server-clean/hw/xfree86/os-support/shared/sigio.c ++++ xorg-server-workdir/hw/xfree86/os-support/shared/sigio.c +@@ -56,6 +56,9 @@ + #include + #endif + ++#include ++#include ++ + #include + #include + #include "xf86.h" +diff --git xorg-server-clean/include/os.h xorg-server-workdir/include/os.h +index 7db2408..8862645 100644 +--- xorg-server-clean/include/os.h ++++ xorg-server-workdir/include/os.h +@@ -54,6 +54,7 @@ SOFTWARE. + #include /* for reallocarray */ + #endif + #include ++#include + #ifdef MONOTONIC_CLOCK + #include + #endif +diff --git xorg-server-clean/mi/mibitblt.c xorg-server-workdir/mi/mibitblt.c +index 0b13e49..aff6539 100644 +--- xorg-server-clean/mi/mibitblt.c ++++ xorg-server-workdir/mi/mibitblt.c +@@ -49,6 +49,8 @@ SOFTWARE. + #include + #endif + ++#include ++ + #include + #include + +diff --git xorg-server-clean/os/access.c xorg-server-workdir/os/access.c +index 61ee8e3..24cabae 100644 +--- xorg-server-clean/os/access.c ++++ xorg-server-workdir/os/access.c +@@ -120,7 +120,7 @@ SOFTWARE. + #include + #endif + +-#if defined(SVR4) || (defined(SYSV) && defined(__i386__)) || defined(__GNU__) ++#if defined(SVR4) || (defined(SYSV) && defined(__i386__)) || defined(__GNU__) || defined(__aero__) + #include + #endif + #if defined(SYSV) && defined(__i386__) +diff --git xorg-server-clean/os/ospoll.c xorg-server-workdir/os/ospoll.c +index c68aabc..a3217dc 100644 +--- xorg-server-clean/os/ospoll.c ++++ xorg-server-workdir/os/ospoll.c +@@ -45,11 +45,13 @@ + #define HAVE_OSPOLL 1 + #endif + ++/* + #if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1) + #include + #define EPOLL 1 + #define HAVE_OSPOLL 1 + #endif ++*/ + + #if !HAVE_OSPOLL + #include "xserver_poll.h" +diff --git xorg-server-clean/os/utils.c xorg-server-workdir/os/utils.c +index 92a66e8..f29b359 100644 +--- xorg-server-clean/os/utils.c ++++ xorg-server-workdir/os/utils.c +@@ -1403,7 +1403,7 @@ System(const char *command) + return -1; + } + +- return p == -1 ? -1 : status; ++ return p == -1 ? -1 : !WIFEXITED(status) || WEXITSTATUS(status); + } + + static struct pid { +@@ -1475,7 +1475,7 @@ Popen(const char *command, const char *type) + } + close(pdes[1]); + } +- execl("/bin/sh", "sh", "-c", command, (char *) NULL); ++ execl("/usr/bin/sh", "sh", "-c", command, (char *) NULL); + _exit(127); + } + +@@ -1633,7 +1633,7 @@ Pclose(void *iop) + } + #endif + +- return pid == -1 ? -1 : pstat; ++ return pid == -1 ? -1 : !WIFEXITED(pstat) || WEXITSTATUS(pstat); + } + + int diff --git a/patches/xorg-xinit/jinx-working-patch.patch b/patches/xorg-xinit/jinx-working-patch.patch new file mode 100644 index 00000000000..b21b01acafb --- /dev/null +++ b/patches/xorg-xinit/jinx-working-patch.patch @@ -0,0 +1,13 @@ +diff --git xorg-xinit-clean/startx.cpp xorg-xinit-workdir/startx.cpp +index dfbebe1..99a0586 100644 +--- xorg-xinit-clean/startx.cpp ++++ xorg-xinit-workdir/startx.cpp +@@ -127,6 +127,8 @@ if defaults read $X11_PREFS_DOMAIN 2> /dev/null | grep -q 'dpi' && defaults read + defaultserverargs="$defaultserverargs -dpi `defaults read $X11_PREFS_DOMAIN dpi`" + fi + ++#elif defined(__aero__) ++enable_xauth=0 + #else + enable_xauth=1 + #endif diff --git a/patches/zlib/0001-zlib-aero-specific-changes.patch b/patches/zlib/0001-zlib-aero-specific-changes.patch deleted file mode 100644 index 4efc38d0efa..00000000000 --- a/patches/zlib/0001-zlib-aero-specific-changes.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b0efeeaf9b78c440328295f17224fa3128d85d7d Mon Sep 17 00:00:00 2001 -From: Andy-Python-Programmer -Date: Tue, 28 Jun 2022 17:38:43 +1000 -Subject: [PATCH] zlib: aero specific changes - -Signed-off-by: Andy-Python-Programmer ---- - configure | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure b/configure -index 52ff4a0..6fbfb91 100755 ---- a/configure -+++ b/configure -@@ -218,7 +218,7 @@ if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then - uname=`(uname -s || echo unknown) 2>/dev/null` - fi - case "$uname" in -- Linux* | linux* | GNU | GNU/* | solaris*) -+ Linux* | linux* | GNU | GNU/* | solaris* | aero*) - LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} ;; - *BSD | *bsd* | DragonFly) - LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} --- -2.25.1 - diff --git a/recipes/at-spi2-core b/recipes/at-spi2-core new file mode 100644 index 00000000000..901136259c6 --- /dev/null +++ b/recipes/at-spi2-core @@ -0,0 +1,22 @@ +name=at-spi2-core +version=2.51.0 +revision=1 +tarball_url="https://download.gnome.org/sources/at-spi2-core/2.51/at-spi2-core-${version}.tar.xz" +tarball_blake2b="67a622f1ffba322183c6c04c8de6311bceb48f6ad6d34ad7bc33b22ab0c695a5395b5aad729eff699ab1c0525d1a4059c30899b03be8656e87204ec4333e432c" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs dbus glib libxml" + +build() { + meson_configure \ + -Dsystemd_user_dir=/tmp \ + -Dintrospection=disabled + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/autoconf-archive b/recipes/autoconf-archive new file mode 100644 index 00000000000..5e70163b0cf --- /dev/null +++ b/recipes/autoconf-archive @@ -0,0 +1,12 @@ +name=autoconf-archive +version=2023.02.20 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/autoconf-archive/autoconf-archive-${version}.tar.xz" +tarball_blake2b="a72469e61a6ef702cbf4e30712c7dbe36369da7dad6e2312eb7026af41a989a47ded0a27975349486b69155f9e8199f89720dc57f98440b2766294a0f8755ee6" + +package() { + mkdir -p "${dest_dir}${prefix}"/share/aclocal + cp -r "${source_dir}"/m4/. "${dest_dir}${prefix}"/share/aclocal/ + + post_package_strip +} diff --git a/recipes/base-files b/recipes/base-files new file mode 100644 index 00000000000..b29669d9ad3 --- /dev/null +++ b/recipes/base-files @@ -0,0 +1,8 @@ +name=base-files +version=0.0 +revision=1 +source_dir="base-files" + +package() { + cp -rpv ${source_dir}/. "${dest_dir}"/ +} diff --git a/recipes/bash b/recipes/bash new file mode 100644 index 00000000000..82e670a674c --- /dev/null +++ b/recipes/bash @@ -0,0 +1,30 @@ +name=bash +version=5.2.21 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/bash/bash-${version}.tar.gz" +tarball_blake2b="6789c9a0d9eb1ad167d4199bf1438d77934a7bbeae9f9fdd7167cae006b17b3894852440248db1bb6e9cf6d930e8a18b6448a3bb4db8831b2e6d1445b56a2065" +source_hostdeps="autoconf automake libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs ncurses readline" + +regenerate() { + AUTOHEADER=true autoreconf -fvi +} + +build() { + autotools_configure \ + --with-curses \ + --enable-readline \ + --without-bash-malloc \ + --with-installed-readline="${sysroot}/usr/lib" + + make -j${parallelism} +} + +package() { + make install DESTDIR="${dest_dir}" + ln -s bash "${dest_dir}${prefix}"/bin/sh + + post_package_strip +} diff --git a/recipes/binutils b/recipes/binutils new file mode 100644 index 00000000000..5328b30c325 --- /dev/null +++ b/recipes/binutils @@ -0,0 +1,40 @@ +name=binutils +version=2.41 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.xz" +tarball_blake2b="3bccec2b52f7e82a727121bf2a2e51a6249ba63dcd74c665fd834e858645c912ffd8245d848435288b938852830b482905606f55c40df4061215fd75c52ffc75" +source_hostdeps="autoconf-2.69 automake libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf-2.69 automake libtool pkg-config" +deps="core-libs zlib gmp" + +regenerate() { + autotools_recursive_regen -I"$(realpath ./config)" + + cp -pv /usr/local/share/libtool/build-aux/{config.sub,config.guess,install-sh} libiberty/ +} + +build() { + autotools_configure \ + --target=${OS_TRIPLET} \ + --disable-werror \ + --disable-dependency-tracking \ + --enable-colored-disassembly \ + --with-system-zlib \ + --with-gmp=${sysroot_dir}/usr + + SFRAME_LIB_PATH="-L$(pwd -P)/libsframe/.libs" \ + make -j${parallelism} all +} + +package() { + DESTDIR="${dest_dir}" make install + + # Remove unnecessary directory + rm -rf "${dest_dir}${prefix}"/${OS_TRIPLET} + + # Remove static libraries + rm -rf "${dest_dir}${prefix}"/lib/*.a + + post_package_strip +} diff --git a/recipes/bzip2 b/recipes/bzip2 new file mode 100644 index 00000000000..f0f064df6af --- /dev/null +++ b/recipes/bzip2 @@ -0,0 +1,66 @@ +name=bzip2 +version=1.0.8 +revision=1 +tarball_url="https://sourceware.org/ftp/bzip2/bzip2-${version}.tar.gz" +tarball_blake2b="22ab3acd84f4db8c3d6f59340c252faedfd4447cea00dafbd652e65b6cf8a20adf6835c22e58563004cfafdb15348c924996230b4b23cae42da5e25eeac4bdad" +hostdeps="gcc pkg-config" +deps="core-libs" + +build() { + cp -r ${source_dir}/. . + sed -i 's/all: libbz2.a bzip2 bzip2recover test/all: libbz2.a bzip2 bzip2recover/g' Makefile + + make CC=${OS_TRIPLET}-gcc CFLAGS="$CFLAGS -fPIC" -f Makefile-libbz2_so + make clean + make CC=${OS_TRIPLET}-gcc AR=${OS_TRIPLET}-ar CFLAGS="$CFLAGS -fPIC" -j${parallelism} +} + +package() { + mkdir -p "${dest_dir}${prefix}/bin" "${dest_dir}${prefix}/lib" "${dest_dir}${prefix}/lib/pkgconfig" "${dest_dir}${prefix}/include" + install bzip2-shared "${dest_dir}${prefix}/bin/bzip2" + install bzip2recover "${dest_dir}${prefix}/bin/" + install bzdiff "${dest_dir}${prefix}/bin/" + install bzgrep "${dest_dir}${prefix}/bin/" + install bzmore "${dest_dir}${prefix}/bin/" + install libbz2.so.${version} "${dest_dir}${prefix}/lib/" + install -m 644 bzlib.h "${dest_dir}${prefix}/include/" + ln -sf libbz2.so.${version} "${dest_dir}${prefix}/lib/libbz2.so.1.0" + ln -sf libbz2.so.1.0 "${dest_dir}${prefix}/lib/libbz2.so.1" + ln -sf libbz2.so.1 "${dest_dir}${prefix}/lib/libbz2.so" + ln -sf bzdiff "${dest_dir}${prefix}/bin/bzcmp" + ln -sf bzgrep "${dest_dir}${prefix}/bin/bzegrep" + ln -sf bzgrep "${dest_dir}${prefix}/bin/bzfgrep" + ln -sf bzmore "${dest_dir}${prefix}/bin/bzless" + cat <"${dest_dir}${prefix}/lib/pkgconfig/bzip2.pc" +prefix=${prefix} +exec_prefix=${prefix}/bin +libdir=${prefix}/lib +sharedlibdir=${prefix}/lib +includedir=${prefix}/include + +Name: bzip2 +Description: BZip2 compression library +Version: ${version} + +Requires: +Libs: -L${prefix}/lib -lbz2 +Cflags: -I${prefix}/include +EOF + cat <"${dest_dir}${prefix}/lib/pkgconfig/libbz2.pc" +prefix=${prefix} +exec_prefix=${prefix}/bin +libdir=${prefix}/lib +sharedlibdir=${prefix}/lib +includedir=${prefix}/include + +Name: libbz2 +Description: BZip2 compression library +Version: ${version} + +Requires: +Libs: -L${prefix}/lib -lbz2 +Cflags: -I${prefix}/include +EOF + + post_package_strip +} diff --git a/recipes/cairo b/recipes/cairo new file mode 100644 index 00000000000..59ae52ed272 --- /dev/null +++ b/recipes/cairo @@ -0,0 +1,24 @@ +name=cairo +version=1.18.0 +revision=1 +tarball_url="https://cairographics.org/releases/cairo-${version}.tar.xz" +tarball_blake2b="6f6abedb2614e3dd1eed7fcb97cd11296584fb2072617ab3d532bee94e6a83db003ce770d39ba1df84c96a9f6880f4de357f78a22904daf1bb874c9570abd336" +imagedeps="meson ninja binutils" +hostdeps="gcc pkg-config" +deps="core-libs freetype2 fontconfig libpng pixman libxcb libx11 libxext mesa libxrender glib zlib" + +build() { + meson_configure \ + -Dxlib-xcb=enabled \ + -Dzlib=enabled \ + -Dtee=enabled \ + -Dtests=disabled + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/core-libs b/recipes/core-libs new file mode 100644 index 00000000000..32ab76cd3a8 --- /dev/null +++ b/recipes/core-libs @@ -0,0 +1,3 @@ +name=core-libs +revision=1 +deps="mlibc libgcc libstdc++ libintl libiconv libxcrypt" diff --git a/recipes/coreutils b/recipes/coreutils new file mode 100644 index 00000000000..9fd78fd6c79 --- /dev/null +++ b/recipes/coreutils @@ -0,0 +1,41 @@ +name=coreutils +version=9.4 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/coreutils/coreutils-${version}.tar.xz" +tarball_blake2b="83d41c48804c1d470c0e5eed38e692bb6875436dda3f6e2c29784ad6ef563d86e8e066a050e222621b400f78ea4630b1e127d20fc9b76f12096528c42677e35d" +source_imagedeps="gcc gperf" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc gperf" +hostdeps="gcc automake autoconf libtool pkg-config" +deps="core-libs tzdata" + +regenerate() { + autotools_recursive_regen + + # Huge hack: coreutils does not compile the build-machine binary make-prime-list + # using the build-machine compiler. Hence, build and invoke the binary manually here. + mkdir tmp_build_dir + pushd tmp_build_dir + + ../configure + make src/make-prime-list + ./src/make-prime-list 5000 > ../src/primes.h + + popd + rm -rf tmp_build_dir +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + CFLAGS="-DSLOW_BUT_NO_HACKS $CFLAGS" \ + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install-strip + post_package_strip +} diff --git a/recipes/cxxshim b/recipes/cxxshim new file mode 100644 index 00000000000..b10c6bbc26c --- /dev/null +++ b/recipes/cxxshim @@ -0,0 +1,21 @@ +name=cxxshim +version=6f146a41dda736572879fc524cf729eb193dc0a6 +revision=1 +tarball_url="https://github.com/managarm/cxxshim/archive/${version}.tar.gz" +tarball_blake2b="05d8cbad3d46b4272c7e31b1c8041cc5e640cc66853dddf58af953aeba6697dcbc05decb01dc6d4669fec52acd18b3265706dbf710d11dd98e7c1771ac598a49" +imagedeps="meson ninja" +hostdeps="pkg-config" + +build() { + meson_configure \ + --includedir=share/cxxshim/include \ + -Dinstall_headers=true + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/dbus b/recipes/dbus new file mode 100644 index 00000000000..d1cc1b85d6e --- /dev/null +++ b/recipes/dbus @@ -0,0 +1,39 @@ +name=dbus +version=1.15.8 +revision=1 +tarball_url="https://dbus.freedesktop.org/releases/dbus/dbus-${version}.tar.xz" +tarball_blake2b="7c1962dfccc6a1b6250e80b0706d7f44536fabeff009013865ec4b1edaec6d4b47dcbe8f78caa61ef7aef4bac6b79f0e2027dd16bbb2baae328429e648bf8b8c" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="autoconf-archive" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs glib libexpat" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --runstatedir=/run \ + --disable-doxygen-docs \ + --disable-xml-docs \ + --with-systemdsystemunitdir=no \ + --with-systemduserunitdir=no \ + --with-system-pid-file=/run/dbus/pid \ + --with-system-socket=/run/dbus/system_bus_socket \ + --disable-selinux \ + --disable-apparmor \ + --disable-libaudit \ + --disable-kqueue \ + --disable-launchd \ + --disable-systemd \ + --disable-tests + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/findutils b/recipes/findutils new file mode 100644 index 00000000000..8cc615b705d --- /dev/null +++ b/recipes/findutils @@ -0,0 +1,30 @@ +name=findutils +version=4.9.0 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/findutils/findutils-${version}.tar.xz" +tarball_blake2b="3ada8903fc552ad2e580a7b631a4b9d941935b3f4231029564c6f2b7b10ba6f2244e2de57f6d79268c5e0481a193f64edbbae637e7a51ae6f495e3eefabf52c9" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="python" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure \ + --without-selinux + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} + diff --git a/recipes/fontconfig b/recipes/fontconfig new file mode 100644 index 00000000000..4e6189696c7 --- /dev/null +++ b/recipes/fontconfig @@ -0,0 +1,29 @@ +name=fontconfig +version=2.14.2 +revision=1 +tarball_url="https://www.freedesktop.org/software/fontconfig/release/fontconfig-${version}.tar.xz" +tarball_blake2b="4efeeb7f9a6705d493128d00b60e681a20a47556f4c0d7787a5c7a6d2cbbc22f150cad7988a9836a9e72aeb61e2b6a196c00a071c7042c62283c7720cdbb743d" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="python gperf" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs freetype2 libexpat libxml" + +regenerate() { + autotools_recursive_regen + + # Make sure we regenerate this file + rm -f src/fcobjshash.h +} + +build() { + autotools_configure \ + --enable-libxml2 + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/fox b/recipes/fox new file mode 100644 index 00000000000..9e5eb762a7f --- /dev/null +++ b/recipes/fox @@ -0,0 +1,27 @@ +name=fox +version=1.6.57 +revision=1 +tarball_url="http://fox-toolkit.org/ftp/fox-${version}.tar.gz" +tarball_blake2b="3efbc6188225f9444fbd347359e8b4041a08fe654acb99c48e4966e501a2f72a44863f2e9b60ae810a259951f89cfc27b9a8b6341e029627066712e0dbf20e40" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 libxft libxext freetype2 glu" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/freeglut b/recipes/freeglut new file mode 100644 index 00000000000..ca4e5d1f5ae --- /dev/null +++ b/recipes/freeglut @@ -0,0 +1,28 @@ +name=freeglut +version=3.4.0 +revision=1 +tarball_url="https://github.com/FreeGLUTProject/freeglut/releases/download/v${version}/freeglut-${version}.tar.gz" +tarball_blake2b="47b073c4e81473417358452ede3891b6fc36e324f66eec42fcbbadebb2144680e3b52caded504135239e170fd8f30a1fe8b6666a746b06d48cd7226c98a8114e" +imagedeps="gcc ninja python git" +hostdeps="gcc cmake pkg-config" +deps="core-libs libxi mesa glu" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=ON \ + -DFREEGLUT_BUILD_DEMOS=OFF \ + -DFREEGLUT_BUILD_STATIC_LIBS=OFF \ + ${source_dir} + + ninja +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/freetype2 b/recipes/freetype2 new file mode 100644 index 00000000000..a330732f3aa --- /dev/null +++ b/recipes/freetype2 @@ -0,0 +1,21 @@ +name=freetype2 +version=2.13.2 +revision=1 +tarball_url="https://download.savannah.gnu.org/releases/freetype/freetype-${version}.tar.xz" +tarball_blake2b="cebc82180d9afaeb112a65ba78903d7bf7a9295a803166a033585ad2325add6023f05066852240c4665e56285345ba503b01ecd461d48f0478a8f3f56136988e" +source_hostdeps="pkg-config" +imagedeps="meson gcc" +hostdeps="gcc pkg-config" +deps="core-libs bzip2 libpng zlib" + +build() { + meson_configure + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/fribidi b/recipes/fribidi new file mode 100644 index 00000000000..a49d73a6d22 --- /dev/null +++ b/recipes/fribidi @@ -0,0 +1,25 @@ +name=fribidi +version=1.0.13 +revision=1 +tarball_url="https://github.com/fribidi/fribidi/releases/download/v${version}/fribidi-${version}.tar.xz" +tarball_blake2b="8cc31220304ddbdeb0047b30ed9084921920b32ad3f1bdcf29ecbb2fafbd430c391bc99bb7f205546ff8482aea1ef7ed369da71deb3474aa623fc2aeace1b62a" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/frigg b/recipes/frigg new file mode 100644 index 00000000000..4a303d3524b --- /dev/null +++ b/recipes/frigg @@ -0,0 +1,22 @@ +name=frigg +version=dd9d1eab062e8168edafe8d6249524e4e2b157fe +revision=1 +tarball_url="https://github.com/managarm/frigg/archive/${version}.tar.gz" +tarball_blake2b="7d77f563f604a590713733b2f0030d0465dd4abbc304c6e183895146ba57bc3cc73993edee898a7a43eadb97d731297b0fb76d3cfc7e5b2ec61d3ec360cc540d" +imagedeps="gcc meson ninja" +hostdeps="pkg-config" + +build() { + meson_configure \ + --includedir=share/frigg/include \ + --buildtype=debugoptimized \ + -Dbuild_tests=disabled + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/gcc b/recipes/gcc new file mode 100644 index 00000000000..9fe89c5f762 --- /dev/null +++ b/recipes/gcc @@ -0,0 +1,48 @@ +name=gcc +version=13.2.0 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz" +tarball_blake2b="0034b29d3d6cc05821f0c4253ce077805943aff7b370729dd203bda57d89c107edd657eeddc2fb1e69ea15c7b0323b961f46516c7f4af89a3ccf7fea84701be2" +source_hostdeps="automake autoconf-2.69 libtool pkg-config" +source_imagedeps="git" +hostdeps="gcc autoconf-2.69 automake libtool pkg-config" +deps="core-libs binutils zlib gmp mpfr mpc" +imagedeps="gcc" + +regenerate() { + for i in "${base_dir}"/patches/gcc-host/*; do + patch -p1 < "$i" + done + + autotools_recursive_regen -I"$(realpath ./config)" + + cp -pv /usr/local/share/libtool/build-aux/{config.sub,config.guess,install-sh} libiberty/ +} + +build() { + CXXFLAGS_FOR_TARGET="$CFLAGS" \ + CFLAGS_FOR_TARGET="$CFLAGS" \ + autotools_configure \ + --target=${OS_TRIPLET} \ + --with-sysroot=/ \ + --with-build-sysroot=${sysroot_dir} \ + --enable-languages=c,c++,lto \ + --enable-initfini-array \ + --disable-multilib \ + --with-system-zlib \ + --enable-host-shared \ + --with-pkgversion=aero \ + --with-bugurl="https://github.com/Andy-Python-Programmer/aero/issues" + + make -j${parallelism} all-gcc +} + +package() { + DESTDIR="${dest_dir}" make install-gcc + + ln -s gcc "${dest_dir}${prefix}"/bin/cc + # Remove static libraries + rm -rf "${dest_dir}${prefix}"/lib/*.a + + post_package_strip +} diff --git a/recipes/gdk-pixbuf b/recipes/gdk-pixbuf new file mode 100644 index 00000000000..3991fd4537f --- /dev/null +++ b/recipes/gdk-pixbuf @@ -0,0 +1,22 @@ +name=gdk-pixbuf +version=2.42.10 +revision=1 +tarball_url="https://download.gnome.org/sources/gdk-pixbuf/2.42/gdk-pixbuf-${version}.tar.xz" +tarball_blake2b="b6bec388b70a971ea5b336001920fdf433bcbc539d54e62c7b6198e968f0bd3560ef9adc94215b64b01e7d5db69c95d5a1d32654b38b051fceb75e93666b3385" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs glib libjpeg-turbo libpng libx11 libtiff" + +build() { + meson_configure \ + -Dgio_sniffing=false \ + -Dman=false + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/gettext b/recipes/gettext new file mode 100644 index 00000000000..bdceb9d1f3c --- /dev/null +++ b/recipes/gettext @@ -0,0 +1,41 @@ +name=gettext +version=0.22.4 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/gettext/gettext-${version}.tar.xz" +tarball_blake2b="3f93aa5aef8e40d2e01acaa5aeed11efefd0de43ea26d084a0b9e743019685f7584d8e1bf05c1fd5772a5576d21ee1f052b81366f52c7827b6d14bd4d9890edc" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + ( cd gettext-runtime/libasprintf && autoreconf -fvi ) + ( cd gettext-runtime/intl && autoreconf -fvi ) + ( cd gettext-runtime && autoreconf -fvi ) + ( cd gettext-tools && autoreconf -fvi ) + ( cd libtextstyle && autoreconf -fvi ) + autoreconf -fvi +} + +build() { + cp -rp ${source_dir}/. ./ + + ACLOCAL=true \ + AUTOCONF=true \ + AUTOMAKE=true \ + AUTOHEADER=true \ + configure_script_path=./configure \ + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + # Remove conflicting libintl files + rm -f "${dest_dir}${prefix}"/include/libintl.h + rm -f "${dest_dir}${prefix}"/lib/libintl.so* + rm -f "${dest_dir}${prefix}"/share/locale/locale.alias + + post_package_strip +} diff --git a/recipes/glib b/recipes/glib new file mode 100644 index 00000000000..665f67d72ea --- /dev/null +++ b/recipes/glib @@ -0,0 +1,21 @@ +name=glib +version=2.78.1 +revision=1 +tarball_url="https://download.gnome.org/sources/glib/2.78/glib-${version}.tar.xz" +tarball_blake2b="af8f2e83600dfb3ec84702399cb00a3aaedbc80087e35dc7cc2e2374d4fe5fdf82707ac8c911da1c53eb7b027c9da9ecfc1c0a8f56b39431fa4cf44cad5b10f7" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs pcre2 libffi zlib" + +build() { + meson_configure \ + -Dxattr=false + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/glib-networking b/recipes/glib-networking new file mode 100644 index 00000000000..c36d6ab8ef0 --- /dev/null +++ b/recipes/glib-networking @@ -0,0 +1,22 @@ +name=glib-networking +version=2.78.0 +tarball_url="https://gitlab.gnome.org/GNOME/glib-networking/-/archive/${version}/glib-networking-${version}.tar.gz" +tarball_blake2b="a8b73a303f427c8069db9060f4037051b11a5bcc83f5c3673ac3ca630f22de31a911b9a31056e35e59ace52609718f2d4055aac08d1975a158d4a4a135a81204" +deps="core-libs glib openssl" +imagedeps="meson" +hostdeps="gcc pkg-config" + +build() { + meson_configure \ + -Dgnutls=disabled \ + -Dopenssl=enabled \ + -Dinstalled_tests=false \ + -Dlibproxy=disabled \ + -Dgnome_proxy=disabled + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install +} diff --git a/recipes/glu b/recipes/glu new file mode 100644 index 00000000000..70b3e68be9f --- /dev/null +++ b/recipes/glu @@ -0,0 +1,21 @@ +name=glu +version=9.0.3 +revision=1 +tarball_url="https://archive.mesa3d.org/glu/glu-${version}.tar.xz" +tarball_blake2b="a6fc842004dcca4243ef285e26806afdfb931d21985ad8f9a3f03f438e66b810718bf04e588044ed8db99990e49f806d346dc2ce69cfa91450f046a4dfa39136" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs mesa" + +build() { + meson_configure \ + -Dgl_provider=gl + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/gmp b/recipes/gmp new file mode 100644 index 00000000000..7d8981748ff --- /dev/null +++ b/recipes/gmp @@ -0,0 +1,26 @@ +name=gmp +version=6.3.0 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/gmp/gmp-${version}.tar.xz" +tarball_blake2b="a865129e2b3f634ec5bad7f97ed89532e43f5662ac47a7d8ab7f0df8c9f8d0886bd984651422e2573c2163bca69c0547c248147ec90880accbd53db97dc0ddee" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure \ + --enable-cxx + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/graphite2 b/recipes/graphite2 new file mode 100644 index 00000000000..88e477d300c --- /dev/null +++ b/recipes/graphite2 @@ -0,0 +1,25 @@ +name=graphite2 +version=1.3.14 +revision=1 +tarball_url="https://github.com/silnrsi/graphite/releases/download/${version}/graphite2-${version}.tgz" +tarball_blake2b="72bf6736aaa8476a89e44ef53c5b6c94f45d815fe1a451ba6b3696bfe023971210975dee4a9c8cb3042f36442e4efecf5baf171ef4230ad2b10694a89865f918" +imagedeps="ninja python" +hostdeps="gcc cmake pkg-config" +deps="core-libs" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=${prefix} \ + -DCMAKE_BUILD_TYPE=Release \ + ${source_dir} + + ninja +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/grep b/recipes/grep new file mode 100644 index 00000000000..6bc28b421fb --- /dev/null +++ b/recipes/grep @@ -0,0 +1,28 @@ +name=grep +version=3.11 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/grep/grep-${version}.tar.xz" +tarball_blake2b="e21785bca20b5a090d32bb5dc525fb298af30165106ed4c289b1518ea3d2acdcacfd6309b12f13be29a4b958f19588546119c695deb2b7500d49dcff86357bdc" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gperf" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs pcre2" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/gsettings-desktop-schemas b/recipes/gsettings-desktop-schemas new file mode 100644 index 00000000000..f5d0e003206 --- /dev/null +++ b/recipes/gsettings-desktop-schemas @@ -0,0 +1,28 @@ +name=gsettings-desktop-schemas +version=45.0 +revision=1 +tarball_url="https://download.gnome.org/sources/gsettings-desktop-schemas/45/gsettings-desktop-schemas-${version}.tar.xz" +tarball_blake2b="b65c846654fac5a104ad9a7d67546c6fb3d54aada178d58c575d22a8c2adc0057c1f1dc177562740f7ae94d0e17743789ca902db7c2fcc42c844bb66e401eaec" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs glib" + +regenerate() { + sed -i -r 's:"(/system):"/org/gnome\1:g' schemas/*.in +} + +build() { + meson_configure \ + -Dintrospection=false + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + glib-compile-schemas "${dest_dir}${prefix}"/share/glib-2.0/schemas + rm "${dest_dir}${prefix}"/share/glib-2.0/schemas/gschemas.compiled + + post_package_strip +} diff --git a/recipes/gtk+-3 b/recipes/gtk+-3 new file mode 100644 index 00000000000..6b39227fc57 --- /dev/null +++ b/recipes/gtk+-3 @@ -0,0 +1,29 @@ +name=gtk+-3 +version=3.24.41 +revision=1 +tarball_url="https://download.gnome.org/sources/gtk%2B/3.24/gtk%2B-${version}.tar.xz" +tarball_blake2b="fbded114fe2b5c1c7bffe79d0a22d559f97081eb972baf31b5c9bd7190bd1ea2875f1c632d3f3be8233377299f1df15bbffbe45d50cc7ff588e034eb41eb8f6e" +imagedeps="meson ninja gdk-pixbuf2" +hostdeps="gcc pkg-config" +deps="core-libs at-spi2-core cairo glib gdk-pixbuf libx11 libxext libxcb libxinerama libxrender libxrandr libxfixes libxdamage pango fribidi libepoxy libxkbcommon fontconfig freetype2 libxi harfbuzz libxcursor gsettings-desktop-schemas dbus" + +build() { + meson_configure \ + -Dprint_backends=file \ + -Dintrospection=false \ + -Dx11_backend=true \ + -Dbroadway_backend=true \ + -Dwayland_backend=false \ + -Dcolord=no + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + glib-compile-schemas "${dest_dir}${prefix}"/share/glib-2.0/schemas + rm "${dest_dir}${prefix}"/share/glib-2.0/schemas/gschemas.compiled + + post_package_strip +} diff --git a/recipes/harfbuzz b/recipes/harfbuzz new file mode 100644 index 00000000000..9de7c3b06ea --- /dev/null +++ b/recipes/harfbuzz @@ -0,0 +1,35 @@ +name=harfbuzz +version=8.3.0 +revision=1 +tarball_url="https://github.com/harfbuzz/harfbuzz/releases/download/${version}/harfbuzz-${version}.tar.xz" +tarball_blake2b="3749d2ff7955e135cf0d740bf6fe8b5c20a6bbf171480a29e6ae14fde8c26e1457506278b8c66e3b9630cbeb006874c19075c784a575e490c41297274a27fe59" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs graphite2 glib zlib freetype2 cairo icu" + +build() { + cp -rp "${source_dir}"/. ./ + + mkdir build && cd build + + meson_source_dir=.. \ + meson_configure \ + -Dgraphite2=enabled \ + -Dglib=enabled \ + -Dgobject=disabled \ + -Dicu=enabled \ + -Dfreetype=enabled \ + -Dcairo=enabled \ + -Dintrospection=disabled \ + -Dtests=disabled + + ninja -j${parallelism} + + cd .. +} + +package() { + ( cd build && DESTDIR="${dest_dir}" ninja install ) + + post_package_strip +} diff --git a/recipes/icu b/recipes/icu new file mode 100644 index 00000000000..0471c276370 --- /dev/null +++ b/recipes/icu @@ -0,0 +1,36 @@ +name=icu +version=73.1 +revision=1 +tarball_url="https://github.com/unicode-org/icu/releases/download/release-73-1/icu4c-73_1-src.tgz" +tarball_blake2b="45de117efc4a49301c04a997963393967a70b8583abf1a9626331e275c5bc329cf2685de5c80b32f764c8ff2530b5594316d7119ce66503e5adba7842ca24424" +source_hostdeps="autoconf automake libtool pkg-config" +source_deps="autoconf-archive" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen + cp source/config/{mh-linux,mh-unknown} +} + +build() { + mkdir cross-build + cd cross-build + ${source_dir}/source/configure \ + --prefix=/usr/local + make -j${parallelism} + cd .. + + configure_script_path=${source_dir}/source/configure \ + autotools_configure \ + --with-cross-build=$(realpath cross-build) + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/jwm b/recipes/jwm new file mode 100644 index 00000000000..ddf4baf9b91 --- /dev/null +++ b/recipes/jwm @@ -0,0 +1,29 @@ +name=jwm +version=2.4.3 +revision=1 +tarball_url="https://github.com/joewing/jwm/releases/download/v${version}/jwm-${version}.tar.xz" +tarball_blake2b="d0b0ff1088ab3390a90c054162ea2c2fe782b61f28b3fdb28464ace362143fdc94e25ec82f7f4178b86a26c9315cdfcf9a81bff2e76bb5e3d62f88968a4ee80b" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="gettext" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 libxft libjpeg-turbo libxpm libxinerama libpng" + +regenerate() { + AUTOMAKE=true \ + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + autotools_configure \ + --disable-fribidi + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + cp -v "${base_dir}"/build-support/jwm/system.jwmrc "${dest_dir}"/etc/ + post_package_strip +} diff --git a/recipes/less b/recipes/less new file mode 100644 index 00000000000..8307c4b3e45 --- /dev/null +++ b/recipes/less @@ -0,0 +1,24 @@ +name=less +version=643 +revision=1 +tarball_url="https://www.greenwoodsoftware.com/less/less-${version}.tar.gz" +tarball_blake2b="6dc60dc2e8db05afdae466877a1d26a3008ff5378bbbf2fbdf9efc4f87c0fcfde5703d44a24d4355c98d3a5f438bdb51173150f2a69f801d9c8e4a7401d71b53" +source_hostdeps="autoconf automake libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs ncurses" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + make install DESTDIR="${dest_dir}" + + post_package_strip +} diff --git a/recipes/libepoxy b/recipes/libepoxy new file mode 100644 index 00000000000..cbe4ca7b8c1 --- /dev/null +++ b/recipes/libepoxy @@ -0,0 +1,22 @@ +name=libepoxy +version=1.5.10 +revision=1 +tarball_url="https://download.gnome.org/sources/libepoxy/1.5/libepoxy-${version}.tar.xz" +tarball_blake2b="105267b1b19acf8c86e5e9d23741dfc738e014de4f0b30f88e7ec22f98497cc8e006d729f17b5698780ca1dd782bad99f73ae685b2bf882b77670bb6c4b959c9" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs mesa xorg-proto libx11" + +build() { + meson_configure \ + -Degl=no \ + -Dtests=false + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/libexpat b/recipes/libexpat new file mode 100644 index 00000000000..72c936cf16f --- /dev/null +++ b/recipes/libexpat @@ -0,0 +1,24 @@ +name=libexpat +version=2.5.0 +revision=1 +tarball_url="https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-${version}.tar.xz" +tarball_blake2b="670298d076ff3b512a0212170d40cb04c601a11d6b152f215a5302ad3238c69c2386393d7a6c70bc284be35ce97bf27d87115c3391f4bc17406e509d739d3e31" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libffi b/recipes/libffi new file mode 100644 index 00000000000..646bc260f24 --- /dev/null +++ b/recipes/libffi @@ -0,0 +1,24 @@ +name=libffi +version=3.4.4 +revision=1 +tarball_url="https://github.com/libffi/libffi/releases/download/v${version}/libffi-${version}.tar.gz" +tarball_blake2b="189fe1ffe9507f204581b0ab09995dc7e7b761bb4eac7e338e9f5ff81431aebcef6c182c1839c9f9acb2706697a260c67e6d1351cf7e2aed7c4eb5d694f6f8fd" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libfontenc b/recipes/libfontenc new file mode 100644 index 00000000000..da6703de92c --- /dev/null +++ b/recipes/libfontenc @@ -0,0 +1,25 @@ +name=libfontenc +version=1.1.7 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libfontenc-${version}.tar.gz" +tarball_blake2b="538dc45801dd2fc3b18527b5716fd468089206728ce4704416eb0ecd2ed528f951d64e7bf2f779a5852363670724458c966538afcec813a9823f5d04303d1bbb" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-font-util xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto zlib" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libgcc b/recipes/libgcc new file mode 100644 index 00000000000..b635a352529 --- /dev/null +++ b/recipes/libgcc @@ -0,0 +1,35 @@ +name=libgcc +revision=1 +hostdeps="gcc autoconf-2.69 automake libtool pkg-config" +imagedeps="gcc" +deps="mlibc" + +build() { + cd "${base_dir}"/host-builds/gcc/build + + make -j${parallelism} all-target-libgcc +} + +package() { + cd "${base_dir}"/host-builds/gcc/build + + rm -rf tmp_libgcc_dir + mkdir tmp_libgcc_dir + + DESTDIR="$(realpath tmp_libgcc_dir)" make install-target-libgcc + + mkdir -p "${dest_dir}${prefix}" + + cp -r tmp_libgcc_dir/usr/local/lib "${dest_dir}${prefix}"/ + cp -r tmp_libgcc_dir/usr/local/${OS_TRIPLET}/* "${dest_dir}${prefix}"/ + + rm "${dest_dir}${prefix}"/lib/gcc/${OS_TRIPLET}/13.2.0/crti.o + rm "${dest_dir}${prefix}"/lib/gcc/${OS_TRIPLET}/13.2.0/crtn.o + + # Copy libgcc into GCC's tree else it will complain. + mkdir -p "${base_dir}"/host-pkgs/gcc/usr/local/lib + cp -r tmp_libgcc_dir/usr/local/lib/* "${base_dir}"/host-pkgs/gcc/usr/local/lib/ + + rm "${base_dir}"/host-pkgs/gcc/usr/local/lib/gcc/${OS_TRIPLET}/13.2.0/crti.o + rm "${base_dir}"/host-pkgs/gcc/usr/local/lib/gcc/${OS_TRIPLET}/13.2.0/crtn.o +} diff --git a/recipes/libgcrypt b/recipes/libgcrypt new file mode 100644 index 00000000000..f5d51bdd739 --- /dev/null +++ b/recipes/libgcrypt @@ -0,0 +1,31 @@ +name=libgcrypt +version=1.10.3 +revision=1 +tarball_url="https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-${version}.tar.gz" +tarball_blake2b="86636e88a96ed531718eeed7915e7ab4e359b17500f648a075853f575e7a50fbb7dc78d1f2dbf2a96a7c46ced6cafdbbb4b6b31dd2f34e663f05df30f1096c85" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libgpg-error" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure \ + --disable-dev-random \ + --disable-asm \ + --with-libgpg-error-prefix="${sysroot_dir}${prefix}" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libgpg-error b/recipes/libgpg-error new file mode 100644 index 00000000000..26b81051a56 --- /dev/null +++ b/recipes/libgpg-error @@ -0,0 +1,30 @@ +name=libgpg-error +version=1.47 +revision=1 +tarball_url="https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${version}.tar.gz" +tarball_blake2b="f1e185127192396cde5676030217471f31f46b5f8bde9314bfe74039297a608356f89208139245c9efce3cba1ba7609f230219c8c6cab9f24de05ad384c43c7d" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + cp -v src/syscfg/lock-obj-pub.x86_64-unknown-linux-gnu.h src/syscfg/lock-obj-pub.aero.h + + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libice b/recipes/libice new file mode 100644 index 00000000000..b5d07585061 --- /dev/null +++ b/recipes/libice @@ -0,0 +1,25 @@ +name=libice +version=1.1.1 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libICE-${version}.tar.gz" +tarball_blake2b="1acb1cdb5b0fd49451b6e4498061c16fff35711a19a5da2c2de0046b6b3ed6bd6bdccf8d45f7adcdb7f2f685245176488f149b41087e562945754088f18c220b" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto xtrans" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libiconv b/recipes/libiconv new file mode 100644 index 00000000000..f0bfd9cfaaa --- /dev/null +++ b/recipes/libiconv @@ -0,0 +1,32 @@ +name=libiconv +version=1.17 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/libiconv/libiconv-${version}.tar.gz" +tarball_blake2b="1d317dd0655c680a2082c38561cdff51ac1a9181d4734a8bb1e86861dfd66f1a6c0846a90b5b88f3b38b1fa9983d9e563551f27e95a8e329896b71becceae52b" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="binutils" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="mlibc libgcc libstdc++" + +regenerate() { + cp /usr/local/share/aclocal/libtool.m4 ./m4/ + cp /usr/local/share/aclocal/libtool.m4 ./libcharset/m4/ + cp /usr/local/share/libtool/build-aux/ltmain.sh ./build-aux/ + cp /usr/local/share/libtool/build-aux/ltmain.sh ./libcharset/build-aux/ + cp /usr/local/share/aclocal/ltversion.m4 ./m4/ + cp /usr/local/share/aclocal/ltversion.m4 ./libcharset/m4/ + + autotools_recursive_regen -I"${source_dir}"/m4 -I"${source_dir}"/srcm4 +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libintl b/recipes/libintl new file mode 100644 index 00000000000..9ed0db0bac8 --- /dev/null +++ b/recipes/libintl @@ -0,0 +1,39 @@ +name=libintl +from_source=gettext +revision=1 +hostdeps="gcc automake autoconf libtool pkg-config" +deps="mlibc libgcc libstdc++ libiconv" + +build() { + ACLOCAL=true \ + AUTOCONF=true \ + AUTOMAKE=true \ + AUTOHEADER=true \ + autotools_configure \ + --without-emacs \ + --without-lispdir \ + `# Normally this controls nls behavior in general, but the libintl` \ + `# subdir is skipped unless this is explicitly set.` \ + --enable-nls \ + `# This magic flag enables libintl.` \ + --with-included-gettext \ + --disable-c++ \ + --disable-libasprintf \ + --disable-java \ + --enable-threads=posix \ + --disable-curses \ + --without-git \ + --without-cvs \ + --without-bzip2 \ + --without-xz + + sed -i 's/touch $@//g' gettext-runtime/intl/Makefile + + make -C gettext-runtime/intl -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make -C gettext-runtime/intl install + + post_package_strip +} diff --git a/recipes/libjpeg-turbo b/recipes/libjpeg-turbo new file mode 100644 index 00000000000..321b873253c --- /dev/null +++ b/recipes/libjpeg-turbo @@ -0,0 +1,29 @@ +name=libjpeg-turbo +version=2.1.5.1 +revision=1 +tarball_url="https://github.com/libjpeg-turbo/libjpeg-turbo/archive/refs/tags/${version}.tar.gz" +tarball_blake2b="44a6f61594f0d0cfac3e3a63ddfa9dcc940a5249fcd69e6d5324749d62e8a5e575bb2c5de9b651d63f27d6f03927146367cd8b8275aa1f4f51fd412ebac95797" +imagedeps="gcc ninja python git cmake nasm" +hostdeps="gcc pkg-config" +deps="core-libs" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=${prefix} \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_STATIC=FALSE \ + -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib \ + -DWITH_JPEGS=ON \ + -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ + ${source_dir} + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/libnghttp2 b/recipes/libnghttp2 new file mode 100644 index 00000000000..bc08b96ed6f --- /dev/null +++ b/recipes/libnghttp2 @@ -0,0 +1,27 @@ +name=libnghttp2 +version=1.59.0 +tarball_url="https://github.com/nghttp2/nghttp2/releases/download/v${version}/nghttp2-${version}.tar.gz" +tarball_blake2b="167e973844131915ce8c50e8e4cfa6807ca56cdbacf0c5d03b0b9d8846c76020d7ffde492d62a9d5f91801024126f2ff52833a58e1458246dcbbafbf76b8b99c" +imagedeps="ninja python" +hostdeps="gcc cmake pkg-config" +deps="core-libs" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=${prefix} \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_STATIC=FALSE \ + -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib \ + -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ + ${source_dir} + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/libpng b/recipes/libpng new file mode 100644 index 00000000000..f515dd626cf --- /dev/null +++ b/recipes/libpng @@ -0,0 +1,24 @@ +name=libpng +version=1.6.40 +revision=1 +tarball_url="https://download.sourceforge.net/libpng/libpng-${version}.tar.xz" +tarball_blake2b="4dd2df57791ca68cc31ba966b9176ecb37458572c60eef34e31ff0d3266d25ad6ea9d2e8cae6bfaf7932b5c7bc231047d3ed139b3464304c41cc4d89611f5ba8" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs zlib" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libpsl b/recipes/libpsl new file mode 100644 index 00000000000..53ed6a1333a --- /dev/null +++ b/recipes/libpsl @@ -0,0 +1,28 @@ +name=libpsl +version=0.21.5 +tarball_url="https://github.com/rockdaboot/libpsl/releases/download/${version}/libpsl-${version}.tar.gz" +tarball_blake2b="a0076f622b85df99f866de6707850ac216b764bdb68c6d516f4603da42dac8eae3ee4c53d68dbb6af6f779c2c7f1b9caab74c8b558209b1f6823f95c13fc3ceb" +deps="core-libs libunistring libiconv" +hostdeps="gcc pkg-config autoconf automake libtool" +source_hostdeps="automake autoconf libtool pkg-config" +source_imagedeps="gtk-doc" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --disable-asan \ + --disable-cfi \ + --disable-ubsan \ + --disable-man + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libsm b/recipes/libsm new file mode 100644 index 00000000000..570ea264f6a --- /dev/null +++ b/recipes/libsm @@ -0,0 +1,25 @@ +name=libsm +version=1.2.4 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libSM-${version}.tar.gz" +tarball_blake2b="9f05c36f933ddbe66e06a96c7b9f5c23a2b5218da724a838b42ef4b798195c24a2be13e1d5c61bccf7660a4880f78da8452fa93a668f483ce808ce840c2cfcfb" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libice" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libsoup b/recipes/libsoup new file mode 100644 index 00000000000..02838d6237b --- /dev/null +++ b/recipes/libsoup @@ -0,0 +1,27 @@ +name=libsoup +version=3.4.4 +tarball_url="https://gitlab.gnome.org/GNOME/libsoup/-/archive/${version}/libsoup-${version}.tar.gz" +tarball_blake2b="006af4bd6f9e5be63421b33bb5b0204d0013fe1312ce2392cbd7fc609d650dc07fa38849f0d179d7907568e9faa0843a74f54e86fe6803e665865d5fed4d3b36" +deps="core-libs glib glib-networking zlib libxml libpsl sqlite libnghttp2" +imagedeps="meson" +hostdeps="gcc pkg-config" + +build() { + meson_configure \ + -Dintrospection=disabled \ + -Dinstalled_tests=false \ + -Dsysprof=disabled \ + -Ddocs=disabled \ + -Dvapi=disabled \ + -Dtls_check=false \ + -Dbrotli=disabled \ + -Dntlm=disabled \ + -Dgssapi=disabled \ + -Dtests=false + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install +} diff --git a/recipes/libstdc++ b/recipes/libstdc++ new file mode 100644 index 00000000000..3f908ac205b --- /dev/null +++ b/recipes/libstdc++ @@ -0,0 +1,33 @@ +name=libstdc++ +revision=1 +hostdeps="gcc autoconf-2.69 automake libtool pkg-config" +imagedeps="gcc" +deps="mlibc libgcc" + +build() { + cd "${base_dir}"/host-builds/gcc/build + + make -j${parallelism} all-target-libstdc++-v3 +} + +package() { + cd "${base_dir}"/host-builds/gcc/build + + rm -rf tmp_libstdc++_dir + mkdir tmp_libstdc++_dir + + DESTDIR="$(realpath tmp_libstdc++_dir)" make install-target-libstdc++-v3 + + # For some reason this also installs libgcc even though it shouldn't... + # Remove it. + rm -fv tmp_libstdc++_dir/usr/local/${OS_TRIPLET}/lib/libgcc* + + mkdir -p "${dest_dir}${prefix}" + + cp -r tmp_libstdc++_dir/usr/local/share "${dest_dir}${prefix}"/ + cp -r tmp_libstdc++_dir/usr/local/${OS_TRIPLET}/* "${dest_dir}${prefix}"/ + + # Copy libstdc++ and headers into GCC's tree else it will complain. + mkdir -p "${base_dir}"/host-pkgs/gcc/usr/local/${OS_TRIPLET} + cp -r tmp_libstdc++_dir/usr/local/${OS_TRIPLET}/* "${base_dir}"/host-pkgs/gcc/usr/local/${OS_TRIPLET}/ +} diff --git a/recipes/libtasn b/recipes/libtasn new file mode 100644 index 00000000000..16ea5d3bcc3 --- /dev/null +++ b/recipes/libtasn @@ -0,0 +1,29 @@ +name=libtasn +version=4.19.0 +revision=1 +tarball_url="https://au.mirrors.cicku.me/gnu/libtasn1/libtasn1-${version}.tar.gz" +tarball_blake2b="6e8232590cd87da3bfd9182ed44eccdfbdfcc85e88d8cf19fffdb3d600e04694b77079b95bbd822d2c3fff29458ddae0f0440f9c1c19c711923a2507bd19270f" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs glib" +source_imagedeps="gtk-doc" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + autotools_configure \ + --disable-doc + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libtiff b/recipes/libtiff new file mode 100644 index 00000000000..4c22e07b820 --- /dev/null +++ b/recipes/libtiff @@ -0,0 +1,31 @@ +name=libtiff +version=4.6.0 +revision=1 +tarball_url="https://download.osgeo.org/libtiff/tiff-${version}.tar.xz" +tarball_blake2b="3b508b02b0a536c5bc8e67fe4c1b09ae9c830252786ef4764202c14d673d1ef9634694de7a5893a3551dec684d00bad9d0442c7fea7bcd09238b9960d443cf62" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs freeglut libjpeg-turbo zlib zstd xz" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --without-x \ + --enable-zlib \ + --enable-zstd \ + --enable-jpeg \ + --enable-lzma \ + --disable-webp \ + --enable-cxx + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libunistring b/recipes/libunistring new file mode 100644 index 00000000000..14dce176227 --- /dev/null +++ b/recipes/libunistring @@ -0,0 +1,24 @@ +name=libunistring +version=1.1 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/libunistring/libunistring-${version}.tar.xz" +tarball_blake2b="721adc90884006480055b95d0fa06cd862417aa02b467f1e14688292ad9c11f1e33520b14ed5dc2d2724c6df8713d3af1e8032014259d8355156cb72edfcb983" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libwebp b/recipes/libwebp new file mode 100644 index 00000000000..dc99cfc2076 --- /dev/null +++ b/recipes/libwebp @@ -0,0 +1,29 @@ +name=libwebp +version=1.3.2 +revision=1 +tarball_url="https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-${version}.tar.gz" +tarball_blake2b="12b3ff3aa9952dd32ce13656146556d5efb6a66860249a8676721980aee10253a1b0335685a769d995e9954cd305190a8ed1878ba4fefce9dcaf41a3976f9e3d" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libjpeg-turbo libpng freeglut sdl2 libtiff" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --enable-libwebpmux \ + --enable-libwebpdemux \ + --enable-libwebpdecoder \ + --enable-libwebpextras \ + --enable-swap-16bit-csp + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libx11 b/recipes/libx11 new file mode 100644 index 00000000000..97660737e5e --- /dev/null +++ b/recipes/libx11 @@ -0,0 +1,28 @@ +name=libx11 +version=1.8.7 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libX11-${version}.tar.xz" +tarball_blake2b="335d8af91c13aba11255c266c4687a7f66b021207a92485d723b4107601bbabb6a0e5535241a3bcff4ac9a99142730d2b3d2e2eaff86b507fee5b35a2590d792" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xtrans xorg-util-macros" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxcb xtrans" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --disable-ipv6 \ + --with-keysymdefdir=${sysroot_dir}/usr/include/X11 + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxau b/recipes/libxau new file mode 100644 index 00000000000..8739b09e88a --- /dev/null +++ b/recipes/libxau @@ -0,0 +1,25 @@ +name=libxau +version=1.0.11 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXau-${version}.tar.gz" +tarball_blake2b="2c1066e40fe64ebd8b095bb7bac436d3b0d518080b80e93d1def040af390bd08ed3f4f49feb0b4b390a5733e74bf7429c96ddac5f8fbfb904eb25b496676618a" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxaw b/recipes/libxaw new file mode 100644 index 00000000000..bd172a1db7a --- /dev/null +++ b/recipes/libxaw @@ -0,0 +1,25 @@ +name=libxaw +version=1.0.15 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXaw-${version}.tar.gz" +tarball_blake2b="71d7b413f9a5178149871c810122589ec74fb4b1e78e884a1538871afd69ad775c3ff15e0c0b21115700f5c9c0965c65336b4c07c1d1069490e6c214ad0f3af0" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxmu libxpm" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxcb b/recipes/libxcb new file mode 100644 index 00000000000..58a14a40a25 --- /dev/null +++ b/recipes/libxcb @@ -0,0 +1,27 @@ +name=libxcb +version=1.16 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libxcb-${version}.tar.xz" +tarball_blake2b="1ddd5c2e6be8400a0a77db4b5fbd4698996fd1a00984e370b1f712f6b9ce456c8ccfb6992f2973f5eaf8d5b6b75f39b9f51a1458c2432ddb41edd8199b91b3f9" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +imagedeps="python" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxau libxdmcp xcb-proto" + +regenerate() { + autotools_recursive_regen + sed -i 's/pthread-stubs//' "${source_dir}"/configure +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxcomposite b/recipes/libxcomposite new file mode 100644 index 00000000000..3ef215498dc --- /dev/null +++ b/recipes/libxcomposite @@ -0,0 +1,29 @@ +name=libxcomposite +version=0.4.6 +revision=1 +tarball_url="https://gitlab.freedesktop.org/xorg/lib/libxcomposite/-/archive/libXcomposite-${version}/libxcomposite-libXcomposite-${version}.tar.gz" +tarball_blake2b="6603273ca9481e540478d13b37f0f1267d110dc911cfe02cfe6a22d544071e864821cdfc57dc1348d7f17a0004d2cafc8bca00d5b565e2c85fe8a1149ed50224" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 libxfixes xorg-proto" +source_deps="xorg-util-macros" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + autotools_configure \ + --disable-doc + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxcrypt b/recipes/libxcrypt new file mode 100644 index 00000000000..ff6307f100e --- /dev/null +++ b/recipes/libxcrypt @@ -0,0 +1,27 @@ +name=libxcrypt +version=4.4.36 +revision=1 +tarball_url="https://github.com/besser82/libxcrypt/releases/download/v${version}/libxcrypt-${version}.tar.xz" +tarball_blake2b="9f028e0fe2cb7bb4273f3f6d1e579e0fe93cd71eba21286aa7dc078c904ea3cdce38b2955bdcd618853f7657b01aea7e28c4d898680e69fdf75f812b5a304c1d" +source_hostdeps="autoconf automake libtool pkg-config" +imagedeps="python-passlib" +hostdeps="gcc automake autoconf libtool pkg-config" +deps="mlibc libgcc libstdc++" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure \ + --enable-obsolete-api=yes \ + --disable-xcrypt-compat-files + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxcursor b/recipes/libxcursor new file mode 100644 index 00000000000..7456af70e23 --- /dev/null +++ b/recipes/libxcursor @@ -0,0 +1,25 @@ +name=libxcursor +version=1.2.1 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXcursor-${version}.tar.gz" +tarball_blake2b="42ee1c77f9c976541f51044474b6bf60935ee62d3d95298ce9d71c92e612bc12c460c4161c148d7f9c99a9ea76f74b34ca4f4b8980af2ccabd78fdad4752f2f5" +source_hostdeps="autoconf automake libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxrender libxfixes libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxcvt b/recipes/libxcvt new file mode 100644 index 00000000000..90ecdf9bf53 --- /dev/null +++ b/recipes/libxcvt @@ -0,0 +1,20 @@ +name=libxcvt +version=0.1.2 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libxcvt-${version}.tar.xz" +tarball_blake2b="8a4803eb6790fd0ea1520fd31e335f7a363c3606e74837a959453be8819ce0d450af7bb651887a891aa657a5eeac3e4983041060fa5c87b1238c83354e425de7" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs" + +build() { + meson_configure + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/libxdamage b/recipes/libxdamage new file mode 100644 index 00000000000..8523be15e47 --- /dev/null +++ b/recipes/libxdamage @@ -0,0 +1,25 @@ +name=libxdamage +version=1.1.6 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXdamage-${version}.tar.gz" +tarball_blake2b="e8fcdbb3b93b7f3a74b10adbb4ceaccc963c7f9ce4fe0edee5842fde7d26cbb2cf3061f073c9ca400baa8378d06ed83c8c751495febb1aeb86a27058d74b1543" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxfixes" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxdmcp b/recipes/libxdmcp new file mode 100644 index 00000000000..98bb4e98b2e --- /dev/null +++ b/recipes/libxdmcp @@ -0,0 +1,25 @@ +name=libxdmcp +version=1.1.4 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXdmcp-${version}.tar.gz" +tarball_blake2b="83973212793c93253b06ee75902842873f1f322c53dc32f054954131243dcf5c31d6792dc5d216134c9536c142b4d5823c8fd998d048ec093383b4f7362fb066" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxext b/recipes/libxext new file mode 100644 index 00000000000..15f6708041c --- /dev/null +++ b/recipes/libxext @@ -0,0 +1,25 @@ +name=libxext +version=1.3.5 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXext-${version}.tar.gz" +tarball_blake2b="74ee5d3fc3832fc5d9774f7f1a8e0d30ab1af97c35f0e3da0b314c228f8f511cdb106c74eeeb1de56db16d4c2b8aaab34b7ca886f02530319fde1a7ae7788598" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxfixes b/recipes/libxfixes new file mode 100644 index 00000000000..83eb909d284 --- /dev/null +++ b/recipes/libxfixes @@ -0,0 +1,25 @@ +name=libxfixes +version=6.0.1 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXfixes-${version}.tar.gz" +tarball_blake2b="22be454b2db230057204932ae75aacb2b56523b25b14e501d7e7a2a664e57ae6bcbfa56b6fac4d42d3f8ef770c41debe0eec25451dd70baa9cfc83b1a10e4649" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxfont2 b/recipes/libxfont2 new file mode 100644 index 00000000000..12ba1a1319f --- /dev/null +++ b/recipes/libxfont2 @@ -0,0 +1,28 @@ +name=libxfont2 +version=2.0.6 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXfont2-${version}.tar.gz" +tarball_blake2b="1a871c6d7c81beadf1c9a5e864a2df186b6429337e86f4fee0c8969d158cf284f10019f69a2f7e0c9298d9f6fa842d5315932152b5e70cb068c5530360e578a0" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto xtrans freetype2 bzip2 libfontenc zlib" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --with-bzip2 \ + --disable-devel-docs \ + --disable-selective-werror + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxft b/recipes/libxft new file mode 100644 index 00000000000..18e526bf8f3 --- /dev/null +++ b/recipes/libxft @@ -0,0 +1,25 @@ +name=libxft +version=2.3.8 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXft-${version}.tar.gz" +tarball_blake2b="06d797ed53df793e5b9751bc7984a62a96c973e36d8aa99e4dc96a03e0e7013d6adc9e46f033e1ffcb4632cec2ac0318108ff2894beb4464d44d524254b15328" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxrender fontconfig" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxi b/recipes/libxi new file mode 100644 index 00000000000..4d22d77d791 --- /dev/null +++ b/recipes/libxi @@ -0,0 +1,25 @@ +name=libxi +version=1.8.1 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXi-${version}.tar.gz" +tarball_blake2b="473bf5a80c86ef853dcf21b2292eb07818148302b051ca4fb9bfdf42053ae0ae6c53d588de7c027d1c72d7b5a9dba775111f4913b36e771380f4d0fcb823e345" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxext libxfixes" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxinerama b/recipes/libxinerama new file mode 100644 index 00000000000..c0b0edcfd06 --- /dev/null +++ b/recipes/libxinerama @@ -0,0 +1,25 @@ +name=libxinerama +version=1.1.5 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXinerama-${version}.tar.gz" +tarball_blake2b="ac24af05ae483e7f8476cb5fdf901ae80c592a766387e9f662ceeae5906a55e8529b35fcd01b6893289007e30788fd9e3a507af95870acfa6b25b25b159024a5" +source_hostdeps="autoconf automake libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxext xorg-proto" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxkbcommon b/recipes/libxkbcommon new file mode 100644 index 00000000000..41fff7493a3 --- /dev/null +++ b/recipes/libxkbcommon @@ -0,0 +1,25 @@ +name=libxkbcommon +version=1.6.0 +revision=1 +tarball_url="https://xkbcommon.org/download/libxkbcommon-${version}.tar.xz" +tarball_blake2b="ffd373161f12ea6448a9206f57710355ab65b81ebab5dce74e4dfcee1bdc9175406fc434560648f5933b83cac163099c8564c3add6f51d34856def39ab077850" +imagedeps="meson ninja doxygen" +hostdeps="gcc pkg-config" +deps="core-libs libxcb libxml xkeyboard-config" + +build() { + meson_configure \ + -Dxkb-config-root="$prefix"/share/X11/xkb \ + -Denable-x11=true \ + -Denable-wayland=false + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + mkdir -p "${dest_dir}${prefix}/share/X11/xkb" + + post_package_strip +} diff --git a/recipes/libxkbfile b/recipes/libxkbfile new file mode 100644 index 00000000000..ce39d6814a2 --- /dev/null +++ b/recipes/libxkbfile @@ -0,0 +1,25 @@ +name=libxkbfile +version=1.1.2 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libxkbfile-${version}.tar.gz" +tarball_blake2b="192c0d7a9e9c8f555ccd0a120e79f5d0fb4d9843fe0eb437b5ed5ce62bd65366a50649037aeed9112cd2ca11db4e088282049d4b799bb26d11d2d9b07384a8e1" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxml b/recipes/libxml new file mode 100644 index 00000000000..b8b63d8339a --- /dev/null +++ b/recipes/libxml @@ -0,0 +1,29 @@ +name=libxml +version=2.12.3 +revision=1 +tarball_url="https://download.gnome.org/sources/libxml2/2.12/libxml2-${version}.tar.xz" +tarball_blake2b="12a7c25d2a13d839aac918268b0948a9bd3c352bc29dd09bb975a9b4ff99d299a0e157b1a90f01bdce8ddc36ede9a6834b0dc26635ac775a41bd28d9b2ad7cff" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs zlib icu readline" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure \ + --with-threads \ + --disable-ipv6 \ + --without-python \ + --with-history \ + --with-icu + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxmu b/recipes/libxmu new file mode 100644 index 00000000000..92065a47e65 --- /dev/null +++ b/recipes/libxmu @@ -0,0 +1,25 @@ +name=libxmu +version=1.1.4 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXmu-${version}.tar.gz" +tarball_blake2b="b95188ecd667ffa9d831e547803c16637a968199c4e20d11d8beaf8da19c327aeb655c886f21d6b7d1d2a2b9cce522a091ca791c2626ae74d77f838441fa4a90" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxext libxt" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxpm b/recipes/libxpm new file mode 100644 index 00000000000..be321e49477 --- /dev/null +++ b/recipes/libxpm @@ -0,0 +1,25 @@ +name=libxpm +version=3.5.17 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXpm-${version}.tar.gz" +tarball_blake2b="0acc342fb0aebad04a2d68f60106ad8f52910b2ca65d402bfda09e5914ab92b2b2b9d57680bbb6c6f1c8767971e9cffc1315337f6645fb61940a9cb5ccdf80c0" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxext libxt" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxrandr b/recipes/libxrandr new file mode 100644 index 00000000000..e808fffc200 --- /dev/null +++ b/recipes/libxrandr @@ -0,0 +1,25 @@ +name=libxrandr +version=1.5.4 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXrandr-${version}.tar.gz" +tarball_blake2b="d5dd5ef33c4452fac7d2c5f16afc15d9e2dcb4e721824ca6e412c6a990ab529003e1beea087afad9dedbcceab17953e066700dac7df0b2aac2cec404335ba93f" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libx11 libxrender libxext" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxrender b/recipes/libxrender new file mode 100644 index 00000000000..095c7f39bc9 --- /dev/null +++ b/recipes/libxrender @@ -0,0 +1,25 @@ +name=libxrender +version=0.9.11 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXrender-${version}.tar.gz" +tarball_blake2b="c8d5cf0c925ccf885634ac535b83b6280b49bc354a9c054375ed6db916350f1e5a1892f9937e0726d3d29fec0f531e787e03d76c3a0c0a22ca6c289c28f2287e" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxshmfence b/recipes/libxshmfence new file mode 100644 index 00000000000..0563afddcb8 --- /dev/null +++ b/recipes/libxshmfence @@ -0,0 +1,26 @@ +name=libxshmfence +version=1.3.2 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libxshmfence-${version}.tar.gz" +tarball_blake2b="ae99fff03f94c5b001bd901e446f56e4ed2edbfb140ab92ec471ab910af92d45ceeb623718e65e0b8e9bd301aacf0c5d5d3a31dab0246c824aabe0664957e78e" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --disable-futex + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxslt b/recipes/libxslt new file mode 100644 index 00000000000..13286647680 --- /dev/null +++ b/recipes/libxslt @@ -0,0 +1,36 @@ +name=libxslt +version=1.1.39 +tarball_url="https://gitlab.gnome.org/GNOME/libxslt/-/archive/v${version}/libxslt-v${version}.tar.gz" +tarball_blake2b="c534663795335273fbb0abccaa4bf7df4bf86200fc52a36c4f7e71ab30158630496665c8886cfd6ecfa3d43bcc475c7b8a1f2839fb288c442063e4b2f0b86d77" +imagedeps="ninja python" +hostdeps="gcc cmake pkg-config" +deps="core-libs libxml" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=${prefix} \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_STATIC=FALSE \ + -DCMAKE_INSTALL_DEFAULT_LIBDIR=lib \ + -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ + -DLIBXSLT_WITH_DEBUGGER=OFF \ + -DLIBXSLT_WITH_CRYPTO=OFF \ + -DLIBXSLT_WITH_MEM_DEBUG=OFF \ + -DLIBXSLT_WITH_MODULES=ON \ + -DLIBXSLT_WITH_PROFILER=OFF \ + -DLIBXSLT_WITH_PYTHON=OFF \ + -DLIBXSLT_WITH_XSLT_DEBUG=OFF \ + -DLIBXSLT_WITH_TESTS=OFF \ + -DLIBXSLT_WITH_THREADS=ON \ + ${source_dir} + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/libxt b/recipes/libxt new file mode 100644 index 00000000000..e4dd3c0652b --- /dev/null +++ b/recipes/libxt @@ -0,0 +1,27 @@ +name=libxt +version=1.3.0 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXt-${version}.tar.gz" +tarball_blake2b="3fc41d02802ccfda270030bcad73c0ca14c5b986d7353d8395339053a4d34352addda83fa2766af3d340c96416361de6a941688aff6e9b5bbc769a34af40bf53" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 libsm" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --with-appdefaultdir=/etc/X11/app-defaults + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxv b/recipes/libxv new file mode 100644 index 00000000000..9e35ba9c3b8 --- /dev/null +++ b/recipes/libxv @@ -0,0 +1,25 @@ +name=libxv +version=1.0.12 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXv-${version}.tar.gz" +tarball_blake2b="21d7d5f40391897d9731ca0772a918d5c33f7de8e3e1307d47e75a44009a74be73a2a47d7751f01e25eabdc6c6ab8889ecda4e266303968b5cec085c38c8edd8" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxext" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/libxxf86vm b/recipes/libxxf86vm new file mode 100644 index 00000000000..285986bed16 --- /dev/null +++ b/recipes/libxxf86vm @@ -0,0 +1,25 @@ +name=libxxf86vm +version=1.1.5 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/libXxf86vm-${version}.tar.gz" +tarball_blake2b="396676748546bf2903a9d5ee8603babc04634d6547b38baed07134a7fea81f1691c064c07a9cc4990aeaf1edc911b586b5e11c449aa7872c1ea5b46879029f5e" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxext" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/linux-headers b/recipes/linux-headers new file mode 100644 index 00000000000..08825729f00 --- /dev/null +++ b/recipes/linux-headers @@ -0,0 +1,21 @@ +name=linux-headers +version=6.6.12 +source_method=tarball +tarball_url="https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz" +tarball_sha512="bb48a1a40d4db13da075ec46420e5abb0a80b4259fedd65883bcf4a67cd11e2d89026a57c370a11f704e9a41973c8bcbc52be12aa10a0e28e17ead59c9d6c4df" +imagedeps="base-devel rsync" + +regenerate() { + true +} + +build() { + cp -rp "${source_dir}"/. ./ +} + +package() { + make headers_install ARCH=x86_64 INSTALL_HDR_PATH=${dest_dir}/${prefix}/ + + # remove this file, as mlibc will override this file with one suited to mlibc + rm -rf ${dest_dir}/${prefix}/include/linux/libc-compat.h +} diff --git a/recipes/llvm b/recipes/llvm new file mode 100644 index 00000000000..c1f425d614e --- /dev/null +++ b/recipes/llvm @@ -0,0 +1,34 @@ +name=llvm +version=17.0.6 +revision=1 +tarball_url="https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-project-${version}.src.tar.xz" +tarball_blake2b="d6ede1a9fda8756995c3e0654111941649e15794179641806f18919f1dc68c41ca0cabd5693b5096d05dccc3a391cd20d34af1137bf8af92ed3117a1ce84d1b2" +imagedeps="gcc ninja python git" +hostdeps="gcc cmake pkg-config" +deps="core-libs zlib" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_LINK_LLVM_DYLIB=ON \ + -DLLVM_ENABLE_RTTI=ON \ + -DLLVM_TARGETS_TO_BUILD=X86 \ + -DLLVM_TARGET_ARCH=x86_64 \ + -DLLVM_DEFAULT_TARGET_TRIPLE=${OS_TRIPLET} \ + -DLLVM_HOST_TRIPLE=${OS_TRIPLET} \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_ENABLE_PROJECTS="llvm;clang;clang-tools-extra" \ + -Wno-dev \ + ${source_dir}/llvm + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/mesa b/recipes/mesa new file mode 100644 index 00000000000..863d6609b25 --- /dev/null +++ b/recipes/mesa @@ -0,0 +1,25 @@ +name=mesa +version=23.3.3 +revision=1 +tarball_url="https://archive.mesa3d.org/mesa-${version}.tar.xz" +tarball_blake2b="6b57e99356abccf398c5fb84953fc1490ddf516dbeed1feca8d16344a04c1c15183325752717447a34a61dd4cdda897147e3194f869d8dbadfa5c45a0c95dab5" +imagedeps="binutils meson ninja python-mako" +hostdeps="gcc pkg-config" +deps="core-libs llvm zlib libxshmfence libxrandr libxdamage libxxf86vm libxfixes libx11 libxext libxcb libexpat" + +build() { + meson_configure \ + -Dglx=xlib \ + -Dplatforms=x11 \ + -Dgallium-drivers=swrast \ + -Dvulkan-drivers= \ + -Dllvm=enabled + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/mesa-demos b/recipes/mesa-demos new file mode 100644 index 00000000000..b3eeaf95831 --- /dev/null +++ b/recipes/mesa-demos @@ -0,0 +1,30 @@ +name=mesa-demos +version=8.5.0 +revision=1 +tarball_url="https://archive.mesa3d.org/demos/${version}/mesa-demos-${version}.tar.gz" +tarball_blake2b="82ded42d845449d925809046d605a30d3f66b5aba57716fdfee99611750001a80aebbda5c66099c3ee9525b655d86e8cf4aeb43adbc939182705ba8fa2ab9c92" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs freetype2 mesa glu libx11 libxext" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --enable-autotools \ + --disable-gles1 \ + --disable-osmesa \ + --disable-libdrm \ + --with-system-data-files \ + --with-glut=no + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/mlibc b/recipes/mlibc new file mode 100644 index 00000000000..50648456585 --- /dev/null +++ b/recipes/mlibc @@ -0,0 +1,28 @@ +name=mlibc +version=7b67d09bde0be6d53284d1583058483e1687880c +revision=1 +tarball_url="https://github.com/managarm/mlibc/archive/${version}.tar.gz" +tarball_blake2b="a18b4fe6ab839088079f5cdcf1d35831ac9f3d25408118f5ddce280d595b730d1cbf7d4869a2da24f4df4edce7d250042acfea67f20266cc7a157db2e1d7c1ed" +imagedeps="meson ninja" +hostdeps="gcc pkg-config libgcc-binaries" +builddeps="cxxshim frigg linux-headers" +deps="mlibc-headers" + +build() { + LDFLAGS="-Wl,/usr/local/libgcc-binaries/libgcc-x86_64.a" \ + meson_configure \ + --buildtype=debugoptimized \ + -Dmlibc_no_headers=true \ + -Ddefault_library=both \ + -Ddisable_crypt_option=true \ + -Ddisable_iconv_option=true \ + -Ddisable_intl_option=true \ + -Ddisable_libgcc_dependency=true \ + -Dlinux_kernel_headers=${sysroot_dir}/${prefix}/include + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install +} diff --git a/recipes/mlibc-headers b/recipes/mlibc-headers new file mode 100644 index 00000000000..e5830247827 --- /dev/null +++ b/recipes/mlibc-headers @@ -0,0 +1,25 @@ +name=mlibc-headers +from_source=mlibc +revision=1 +hostdeps="pkg-config" +imagedeps="meson ninja" +deps="linux-headers" +builddeps="cxxshim frigg" + +build() { + meson setup \ + --cross-file ${base_dir}/userland/cross-file.ini \ + --prefix=${prefix} \ + -Dheaders_only=true \ + -Ddisable_crypt_option=true \ + -Ddisable_iconv_option=true \ + -Ddisable_intl_option=true \ + -Dlinux_kernel_headers=${sysroot_dir}/${prefix}/include \ + ${source_dir} + + ninja +} + +package() { + DESTDIR="${dest_dir}" ninja install +} diff --git a/recipes/mpc b/recipes/mpc new file mode 100644 index 00000000000..0358d280947 --- /dev/null +++ b/recipes/mpc @@ -0,0 +1,26 @@ +name=mpc +version=1.3.1 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/mpc/mpc-${version}.tar.gz" +tarball_blake2b="76434e6f8830af3571836d51576bfebbc9701e9bbb5c4686f134081cd96cd90ae02f7ff42bf9e3957c7a7ba92b6b2d9cdabe18f0269271147521cd7f6a2d551c" +source_imagedeps="git" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs gmp mpfr" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/mpfr b/recipes/mpfr new file mode 100644 index 00000000000..b702c670c62 --- /dev/null +++ b/recipes/mpfr @@ -0,0 +1,33 @@ +name=mpfr +version=4.2.1 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/mpfr/mpfr-${version}.tar.xz" +tarball_blake2b="ad69f53bc910294647523e7613b18a683f1d0f3dd994168ab2a46b66d0371ffa9b8e7cb59495f898470aea69d343e83fc722f11babe4af7b3a12665a1e65860c" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="autoconf-archive" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs gmp" + +regenerate() { + autoreconf -fvi +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure \ + --enable-static=no \ + --enable-shared=yes \ + --enable-thread-safe \ + --with-pic + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/ncurses b/recipes/ncurses new file mode 100644 index 00000000000..e11c0788c8b --- /dev/null +++ b/recipes/ncurses @@ -0,0 +1,51 @@ +name=ncurses +version=6.4.20231111 +revision=1 +tarball_url="https://github.com/ThomasDickey/ncurses-snapshots/archive/refs/tags/v6_4_20231111.tar.gz" +tarball_blake2b="0d7b490b50e58281250cc4ebdac8f35cbb3fbf0e13578524003ae4c26c10507d59fb8dd2a4d67102067df77d857c41e6c37c509d9a7cee8661dd3bb80f7cbfef" +source_hostdeps="autoconf automake libtool pkg-config" +imagedeps="gcc ncurses patchelf" +hostdeps="gcc automake autoconf libtool pkg-config" +deps="core-libs" + +regenerate() { + cp -pv /usr/local/share/libtool/build-aux/config.guess ./ + cp -pv /usr/local/share/libtool/build-aux/config.sub ./ +} + +build() { + cf_cv_func_nanosleep=yes \ + autotools_configure \ + --enable-widec \ + --enable-pc-files \ + --with-shared \ + --with-cxx-shared \ + --without-normal \ + --without-debug \ + --with-manpage-format=normal \ + --with-pkg-config-libdir=/usr/lib/pkgconfig \ + --with-termlib + + make -j${parallelism} +} + +package() { + make install DESTDIR="${dest_dir}" + + # As we build ncurses with wide character support, make some compatibility links + for lib in ncurses ncurses++ form panel menu tinfo ; do + rm -vf "${dest_dir}${prefix}"/lib/lib${lib}.so + echo "INPUT(-l${lib}w)" > "${dest_dir}${prefix}"/lib/lib${lib}.so + ln -sfv ${lib}w.pc "${dest_dir}${prefix}"/lib/pkgconfig/${lib}.pc + # Set library soname + patchelf --set-soname lib${lib}w.so "${dest_dir}${prefix}"/lib/lib${lib}w.so + done + rm -vf "${dest_dir}${prefix}"/lib/libcursesw.so + echo "INPUT(-lncursesw)" > "${dest_dir}${prefix}"/lib/libcursesw.so + ln -sfv libncurses.so "${dest_dir}${prefix}"/lib/libcurses.so + + # Remove static libraries + rm -rf "${dest_dir}${prefix}"/lib/*.a + + post_package_strip +} diff --git a/recipes/neofetch b/recipes/neofetch new file mode 100644 index 00000000000..b832d5ca503 --- /dev/null +++ b/recipes/neofetch @@ -0,0 +1,9 @@ +name=neofetch +version=534b1c8cdbda567066517aeb75d8bdde3641dab7 +tarball_url="https://github.com/Andy-Python-Programmer/neofetch/archive/${version}.tar.gz" +tarball_blake2b="9f9f49a941e70dfe764c38c039c69e21bdf33c72ffbc2cd64a0287c0f8220f8a5ed456ef227da6dc843ef55602f20c9e0ac181cee261e65c373f69ceb5951668" + +package() { + mkdir -p "${dest_dir}/usr/bin" + cp -f "${source_dir}"/neofetch "${dest_dir}"/usr/bin/neofetch +} diff --git a/recipes/nettle b/recipes/nettle new file mode 100644 index 00000000000..c9b60ffba02 --- /dev/null +++ b/recipes/nettle @@ -0,0 +1,25 @@ +name=nettle +version=3.9.1 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/nettle/nettle-${version}.tar.gz" +tarball_blake2b="e3ceaefa19491e58f26b900beaf8b4e746feb2357c7677f5c050f257f4a23c304773446b6283a42a82cf9640e16522b8a71c47f137759f1df23cdeee4625d142" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="gcc" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs gmp" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/openssl b/recipes/openssl new file mode 100644 index 00000000000..951693b31d8 --- /dev/null +++ b/recipes/openssl @@ -0,0 +1,32 @@ +name=openssl +version=1.1.1w +revision=1 +tarball_url="https://github.com/openssl/openssl/releases/download/OpenSSL_1_1_1w/openssl-${version}.tar.gz" +tarball_blake2b="2fdba6ca0188928ab2f74e606136afca66cfa0467170fa6298ef160b64ac6fdcad1e81e5dd14013ce0e9921d0f7417edec531cd0beaf1196fec704c2c6d48395" +hostdeps="gcc pkg-config" +deps="core-libs zlib" + +build() { + CC=${OS_TRIPLET}-gcc \ + CXX=${OS_TRIPLET}-g++ \ + AR=${OS_TRIPLET}-ar \ + ${source_dir}/Configure \ + --prefix=${prefix} \ + --openssldir=/etc/ssl \ + --libdir=lib \ + ${OS_TRIPLET} \ + shared \ + zlib-dynamic \ + no-afalgeng + + make -j${parallelism} +} + +package() { + # Disable installing static libraries. + sed -i '/INSTALL_LIBS/s/libcrypto.a libssl.a//' Makefile + + DESTDIR="${dest_dir}" make DESTDIR="${dest_dir}" MANSUFFIX=ssl install + + post_package_strip +} diff --git a/recipes/pango b/recipes/pango new file mode 100644 index 00000000000..2412c5c14e9 --- /dev/null +++ b/recipes/pango @@ -0,0 +1,21 @@ +name=pango +version=1.51.0 +revision=1 +tarball_url="https://download.gnome.org/sources/pango/1.51/pango-${version}.tar.xz" +tarball_blake2b="d7d343d5fb005b92dc70fc6f65c62d1d22cc81887185612d276e63614e622272117b64051f46aa1ae0348d4ccfbed0a473f9482703d51d5da7e81d1851b49071" +imagedeps="meson ninja" +hostdeps="gcc pkg-config" +deps="core-libs glib fontconfig freetype2 fribidi cairo xorg-proto libx11 xtrans libxext harfbuzz libxft" + +build() { + meson_configure \ + -Dintrospection=disabled + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + post_package_strip +} diff --git a/recipes/pcre2 b/recipes/pcre2 new file mode 100644 index 00000000000..baf6c779c99 --- /dev/null +++ b/recipes/pcre2 @@ -0,0 +1,31 @@ +name=pcre2 +version=10.42 +revision=1 +tarball_url="https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${version}/pcre2-${version}.tar.gz" +tarball_blake2b="19233ee4a63d3bc0828f68c646ecbeb8161c242e52c9242976d80b805d5863699766a8f3a23946ac50ced75f48aad6d948bd9aa3fdc7540bd9193065ea7ee9d1" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs bzip2 ncurses readline zlib" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure \ + --enable-unicode \ + --enable-jit \ + --enable-pcre2-16 \ + --enable-pcre2-32 \ + --enable-pcre2grep-libz \ + --enable-pcre2grep-libbz2 \ + --enable-pcre2test-libreadline + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/pixman b/recipes/pixman new file mode 100644 index 00000000000..f1f294f5fa9 --- /dev/null +++ b/recipes/pixman @@ -0,0 +1,24 @@ +name=pixman +version=0.42.2 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/pixman-${version}.tar.xz" +tarball_blake2b="6286a9d064a5a24017fccbb0a6e9f6ef932077c2e33ec043826d4a7a6c707c9111d3de4b806cbcdb47fc2794f1f930d24d078de1ff2912061967db0890540957" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libpng" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/python b/recipes/python new file mode 100644 index 00000000000..5426ea68b76 --- /dev/null +++ b/recipes/python @@ -0,0 +1,47 @@ +name=python +version=3.13.0 +tarball_url="https://www.python.org/ftp/python/${version}/Python-${version}a1.tar.xz" +tarball_blake2b="62612d22ce652f4b1d7ce93aa30bd5814dbf271dbe98e321b99d003d7da8f74798e55f556db75fc39b676295c1d1f7b31919c444fe3c667d2fbd2ea16799a211" +imagedeps="gcc" +source_deps="autoconf-archive" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libexpat" + +regenerate() { + autotools_recursive_regen +} + +build() { + mkdir -p ./build + cd ./build + + # XXX make this a host dep + if ! [ -f built ]; then + ${source_dir}/configure + + make -j${parallelism} + touch built + fi + + cd - + + CONFIG_SITE=${base_dir}/build-support/python/python-config-site autotools_configure \ + --with-system-ffi \ + --with-system-expat \ + --disable-ipv6 \ + --without-ensurepip \ + --host=x86_64-aero \ + --build=x86_64-linux-gnu \ + --with-build-python="$(pwd -P)/build/python" \ + --with-pkg-config=yes + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + ln -sv python3 "${dest_dir}${prefix}/bin/python" + post_package_strip +} + diff --git a/recipes/readline b/recipes/readline new file mode 100644 index 00000000000..2f72afa724c --- /dev/null +++ b/recipes/readline @@ -0,0 +1,32 @@ +name=readline +version=8.2 +revision=1 +tarball_url="https://ftp.gnu.org/gnu/readline/readline-${version}.tar.gz" +tarball_blake2b="7974322b9c092a756a79e537df08e8532f8e0fcb598f77732e28287c33ebec9e9837ed88b43334c310892d56a871b423903f0f564def2fbe700a1004f2ae7b18" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="patchelf" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs ncurses" + +regenerate() { + AUTOHEADER=true autoreconf -fvi +} + +build() { + autotools_configure \ + --enable-multibyte \ + --with-curses + + make SHLIB_LIBS="-lncursesw" -j${parallelism} +} + +package() { + make SHLIB_LIBS="-lncursesw" install DESTDIR="${dest_dir}" + + # libraries are created without soname... fix that + for lib in libhistory.so.8 libreadline.so.8; do + patchelf --set-soname $lib "${dest_dir}${prefix}/lib/$lib" + done + + post_package_strip +} diff --git a/recipes/sdl2 b/recipes/sdl2 new file mode 100644 index 00000000000..1d571174de4 --- /dev/null +++ b/recipes/sdl2 @@ -0,0 +1,59 @@ +name=sdl2 +version=2.28.5 +revision=1 +tarball_url="https://github.com/libsdl-org/SDL/releases/download/release-${version}/SDL2-${version}.tar.gz" +tarball_blake2b="c96481bc02af6b6d077247238f7e46b0e3ec216664584add29cafb0a91d06dc6ddc637a01519dbd7182d4fa59cfaf26ad6733f72583021cf65849416f9c4b698" +imagedeps="gcc ninja git" +hostdeps="gcc cmake pkg-config" +deps="core-libs libx11 libxext libxcursor libxi libxfixes libxrandr libxrender libxxf86vm mesa" + +build() { + cmake \ + -GNinja \ + -DCMAKE_TOOLCHAIN_FILE=${base_dir}/userland/CMakeToolchain-x86_64.cmake \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=Release \ + -DSDL_ALTIVEC=OFF \ + -DSDL_DISKAUDIO=OFF \ + -DSDL_DIRECTFB=ON \ + -DSDL_OPENGL=ON \ + -DSDL_OPENGLES=ON \ + -DSDL_PTHREADS=ON \ + -DSDL_PTHREADS_SEM=OFF \ + -DSDL_OSS=OFF \ + -DSDL_ALSA=OFF \ + -DSDL_JACK=OFF \ + -DSDL_ESD=OFF \ + -DSDL_PULSEAUDIO=OFF \ + -DSDL_ARTS=OFF \ + -DSDL_NAS=OFF \ + -DSDL_SNDIO=OFF \ + -DSDL_FUSIONSOUND=OFF \ + -DSDL_LIBSAMPLERATE=OFF \ + -DSDL_RPATH=OFF \ + -DSDL_X11=ON \ + -DSDL_WAYLAND=OFF \ + -DSDL_WAYLAND_QT_TOUCH=OFF \ + -DSDL_RPI=OFF \ + -DSDL_COCOA=OFF \ + -DSDL_DIRECTX=OFF \ + -DSDL_WASAPI=OFF \ + -DSDL_RENDER_D3D=OFF \ + -DSDL_VIVANTE=OFF \ + -DSDL_VULKAN=OFF \ + -DSDL_KMSDRM=OFF \ + -DSDL_HIDAPI=OFF \ + -DSDL_SHARED=ON \ + -DSDL_STATIC=OFF \ + ${source_dir} + + ninja -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" ninja install + + rm "${dest_dir}${prefix}"/lib/{libSDL2_test.a,libSDL2main.a} + + post_package_strip +} diff --git a/recipes/sqlite b/recipes/sqlite new file mode 100644 index 00000000000..3263142a692 --- /dev/null +++ b/recipes/sqlite @@ -0,0 +1,27 @@ +name=sqlite +version=3.45.0 +revision=1 +tarball_url="https://sqlite.org/2024/sqlite-autoconf-3450000.tar.gz" +tarball_blake2b="04ba8522be5fa8c0a0a101824f90030f83ad131b53dff622e0449d31b3ee3e50888ed0d8a663c5be3f7338d5d5b6efef1b828374fa599a675ab892bbbb3abec9" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs readline zlib" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --enable-readline \ + --enable-fts5 \ + CFLAGS="$CFLAGS -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_UNLOCK_NOTIFY=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 -DSQLITE_SECURE_DELETE=1 -DSQLITE_ENABLE_FTS3_TOKENIZER=1" + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/ttf-dejavu b/recipes/ttf-dejavu new file mode 100644 index 00000000000..8ea14bc4732 --- /dev/null +++ b/recipes/ttf-dejavu @@ -0,0 +1,15 @@ +name=ttf-dejavu +version=2.37 +revision=1 +tarball_url="https://sourceforge.net/projects/dejavu/files/dejavu/${version}/dejavu-fonts-ttf-${version}.tar.bz2" +tarball_blake2b="d8614907887f20967fc7c75cb33b636a0eb5c682a076ccc7aef09f4ac243507afc005ef90d0b2aeee6a4a6a1ff3d5ce4fac0d1722a382525b3883ef53cdec26a" +deps="core-libs" + +build() { + cp -r ${source_dir}/. ./ +} + +package() { + mkdir -p "${dest_dir}${prefix}/share/fonts/truetype" + cp -r ttf/* "${dest_dir}${prefix}/share/fonts/truetype/" +} diff --git a/recipes/tzdata b/recipes/tzdata new file mode 100644 index 00000000000..a550b3957c1 --- /dev/null +++ b/recipes/tzdata @@ -0,0 +1,57 @@ +name=tzdata +version=2023c +revision=1 +tarball_url="https://data.iana.org/time-zones/releases/tzdata${version}.tar.gz" +tarball_blake2b="8a50aa5f338565d86b8fa5428c138b251bd8dcc3ea66c144b49625d02c5c7aa27f1ace66babd36f10f75cf5eb832ec327b9c2e8adb0384c450130d1ee8c45562" +imagedeps="tzdata" +hostdeps="gcc binutils" +deps="core-libs" + +build() { + cp -r ${source_dir}/. ./ +} + +package() { + # Create the required directories + mkdir -p ${dest_dir}/etc + mkdir -p ${dest_dir}/usr/share/zoneinfo/posix + mkdir -p ${dest_dir}/usr/share/zoneinfo/right + + # Create the time zone files without leap seconds, convention puts these in both zoneinfo and zoneinfo/posix. + # After that. create time time zone files with leap seconds + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo etcetera + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix etcetera + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right etcetera + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo southamerica + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix southamerica + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right southamerica + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo northamerica + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix northamerica + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right northamerica + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo europe + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix europe + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right europe + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo africa + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix africa + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right africa + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo antarctica + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix antarctica + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right antarctica + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo asia + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix asia + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right asia + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo australasia + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix australasia + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right australasia + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo backward + zic -L /dev/null -d "${dest_dir}"/usr/share/zoneinfo/posix backward + zic -L "${source_dir}"/leapseconds -d "${dest_dir}"/usr/share/zoneinfo/right backward + + # Create the posixrules file, POSIX requires daylight saving rules to be in accordance with US rules, thus use New York + zic -d ${dest_dir}/usr/share/zoneinfo -p America/New_York + + # Default to UTC for localtime, this should be fixed, but that is pending xbstrap support. + ln -sf /usr/share/zoneinfo/UTC "${dest_dir}"/etc/localtime + + post_package_strip +} diff --git a/recipes/userland b/recipes/userland new file mode 100644 index 00000000000..f8ad9d22568 --- /dev/null +++ b/recipes/userland @@ -0,0 +1,19 @@ +name=userland +version=0.0 +revision=1 +source_dir="userland" +hostdeps="gcc binutils rust" +deps="core-libs" +imagedeps="rust" +allow_network=yes + +build() { + cp -r "${source_dir}"/. ./ + + make -j${parallelism} CC=x86_64-aero-gcc CXX=x86_64-aero-g++ +} + +package() { + make install PREFIX="${prefix}" DESTDIR="${dest_dir}" + post_package_strip +} diff --git a/recipes/xcb-proto b/recipes/xcb-proto new file mode 100644 index 00000000000..bee617424e3 --- /dev/null +++ b/recipes/xcb-proto @@ -0,0 +1,25 @@ +name=xcb-proto +version=1.16.0 +revision=1 +tarball_url="https://www.x.org/archive/individual/proto/xcb-proto-${version}.tar.xz" +tarball_blake2b="1c59ae4c71e697bd4f0298f6e0ea5235fc47baa9cf584e079258f1da8be538d1b67dc45f1325d82495247d0f8020d0244ca334de3794b410a1feaceabd6b285e" +source_hostdeps="automake autoconf libtool pkg-config" +imagedeps="python libxml2" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xcb-util b/recipes/xcb-util new file mode 100644 index 00000000000..690bb6b1390 --- /dev/null +++ b/recipes/xcb-util @@ -0,0 +1,26 @@ +name=xcb-util +version=0.4.1 +revision=1 +tarball_url="https://xcb.freedesktop.org/dist/xcb-util-${version}.tar.xz" +tarball_blake2b="bcde73073590c56771af6233f1a04a692197a756ef9ce70b6e0bd3625ad6d61f99f4c671dcfae39c8dd66e3225f40f7e9b42dd115ffe83a561e48a9808bf00e3" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +imagedeps="python" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto libxcb" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xf86-input-keyboard b/recipes/xf86-input-keyboard new file mode 100644 index 00000000000..0bc813a7d52 --- /dev/null +++ b/recipes/xf86-input-keyboard @@ -0,0 +1,25 @@ +name=xf86-input-keyboard +version=2.0.0 +revision=1 +tarball_url="https://www.x.org/releases/individual/driver/xf86-input-keyboard-${version}.tar.gz" +tarball_blake2b="f3aa3fca15fc75f8314b7b7248ccb757d667b2c46b22c8e23278d144f30d56515d1aa4190ca82e0c15770550a16dd860fd98a81172dab2e97b04e65fceb2a333" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-server xorg-util-macros libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xf86-input-mouse b/recipes/xf86-input-mouse new file mode 100644 index 00000000000..e9dc1dd7458 --- /dev/null +++ b/recipes/xf86-input-mouse @@ -0,0 +1,25 @@ +name=xf86-input-mouse +version=1.9.5 +revision=1 +tarball_url="https://xorg.freedesktop.org/archive/individual/driver/xf86-input-mouse-${version}.tar.gz" +tarball_blake2b="67f4de10424d640913fcafc2292f342a1e993d33e4ecc3c152e818953e19deaba796b96c29e0c07a4f4b74a1eb3bc1c41c3e5ab868cade02c21a90e2556da53f" +source_hostdeps="autoconf automake libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-server xorg-util-macros libx11" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xf86-video-fbdev b/recipes/xf86-video-fbdev new file mode 100644 index 00000000000..c4bed64eb79 --- /dev/null +++ b/recipes/xf86-video-fbdev @@ -0,0 +1,27 @@ +name=xf86-video-fbdev +version=0.5.0 +revision=1 +tarball_url="https://www.x.org/releases/individual/driver/xf86-video-fbdev-${version}.tar.gz" +tarball_blake2b="0e37c9145582d317c690c8adcfd5bf4b6046cc60e0b9a59382d1cb39878664e46a47d810d8d0d75c7c6b74630ae5e9f377217b51b23d6cfb2661d901a8bf41e2" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-server xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-server xorg-util-macros" + +regenerate() { + autotools_recursive_regen +} + +build() { + SYSROOT=${sysroot_dir} \ + autotools_configure \ + --disable-pciaccess + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xfe b/recipes/xfe new file mode 100644 index 00000000000..67bc76c6b6f --- /dev/null +++ b/recipes/xfe @@ -0,0 +1,30 @@ +name=xfe +version=1.46 +revision=1 +tarball_url="https://downloads.sourceforge.net/sourceforge/xfe/xfe-${version}.tar.xz" +tarball_blake2b="d7b85e5280d1d9d6db3737f8ac14f4248ae4e99b52d843b51468299bdf71581003b21d0fb2be9949c7189481ed5f3fe88bbd146d2185c17dea3a4785edb876b7" +source_hostdeps="autoconf automake libtool pkg-config intltool" +source_deps="xorg-util-macros gettext" +imagedeps="perl-xml-parser" +hostdeps="gcc autoconf automake libtool pkg-config intltool" +deps="core-libs fox libx11 libxft libxcb xcb-util" + +regenerate() { + autotools_recursive_regen +} + +build() { + cp -rp "${source_dir}"/. ./ + + configure_script_path=./configure \ + autotools_configure \ + --with-x + + make -j${parallelism} +} + +package() { + make DESTDIR=${dest_dir} install + + post_package_strip +} diff --git a/recipes/xkeyboard-config b/recipes/xkeyboard-config new file mode 100644 index 00000000000..7089177e1f8 --- /dev/null +++ b/recipes/xkeyboard-config @@ -0,0 +1,27 @@ +name=xkeyboard-config +version=2.34 +revision=1 +tarball_url="https://www.x.org/archive/individual/data/xkeyboard-config/xkeyboard-config-${version}.tar.gz" +tarball_blake2b="dcd4e7b0b8daf146b92fbb56c64eb32b7d2f42d75a8716226e5bc13b30624aca3ac95e97541561ba2429d5089f6dad495111b1a3f4a76b02d10dbe249461f921" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +imagedeps="python" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-xkbcomp" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --with-xkb-rules-symlink=xorg + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-font-util b/recipes/xorg-font-util new file mode 100644 index 00000000000..91d91bab718 --- /dev/null +++ b/recipes/xorg-font-util @@ -0,0 +1,25 @@ +name=xorg-font-util +version=1.4.1 +revision=1 +tarball_url="https://www.x.org/archive/individual/font/font-util-${version}.tar.xz" +tarball_blake2b="5a7cee52aa58cecc85f5168963038b65d921bc33615e86a833cba5aec007d61bb05fa3b200ed9b192d9ab9291d53065443711f8eac976242b2013cd7b9fc494a" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-proto b/recipes/xorg-proto new file mode 100644 index 00000000000..c914cf0042a --- /dev/null +++ b/recipes/xorg-proto @@ -0,0 +1,25 @@ +name=xorg-proto +version=2023.2 +revision=1 +tarball_url="https://www.x.org/releases/individual/proto/xorgproto-${version}.tar.xz" +tarball_blake2b="ff255b91770ad11cdcc48d12815317285d8d16d28011a86166f3e07af18b30fdf35c2eb7b6537504eb4c0e9ca65b3116493422b6faebe04ee80e6aee92387675" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-server b/recipes/xorg-server new file mode 100644 index 00000000000..ce2985cbc62 --- /dev/null +++ b/recipes/xorg-server @@ -0,0 +1,52 @@ +name=xorg-server +version=21.1.11 +revision=1 +tarball_url="https://www.x.org/releases/individual/xserver/xorg-server-${version}.tar.xz" +tarball_blake2b="0a18840979bb8b20b02eca9d737f20ddcf92a4771386074c38692df8a1c9b0f471af2211f3006f845ad0dd887b3844b7e7aac761bc12fc4e4177f1ada32ec503" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xtrans xorg-font-util xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs xorg-proto xcb-proto xtrans libxinerama libxcvt libxshmfence libx11 libxaw libxxf86vm libxkbfile libxmu libxfont2 libepoxy libxi libxv libxdamage libxrender libxrandr libxcb libxfixes libxext nettle xorg-xkbcomp xkeyboard-config pixman" + +regenerate() { + autotools_recursive_regen +} + +build() { + CFLAGS="-Wno-error=array-bounds ${common_flags}" \ + autotools_configure \ + --with-xkb-bin-directory=/usr/bin \ + --with-xkb-path=/usr/share/X11/xkb \ + --with-xkb-output=/var/lib/xkb \ + --with-fontrootdir=/usr/share/fonts/X11 \ + --enable-xorg \ + --enable-xv \ + --enable-xvfb \ + --disable-xephyr \ + --disable-xnest \ + --disable-suid-wrapper \ + --disable-pciaccess \ + --disable-dpms \ + --disable-screensaver \ + --disable-xres \ + --disable-xvmc \ + --disable-systemd-logind \ + --disable-secure-rpc \ + --disable-config-udev \ + --disable-dri \ + --disable-dri2 \ + --disable-dri3 \ + --disable-int10-module \ + --disable-vgahw \ + --disable-libdrm \ + --disable-glamor \ + --disable-glx + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-util-macros b/recipes/xorg-util-macros new file mode 100644 index 00000000000..8d798f7f3fb --- /dev/null +++ b/recipes/xorg-util-macros @@ -0,0 +1,24 @@ +name=xorg-util-macros +version=1.20.0 +revision=1 +tarball_url="https://www.x.org/archive/individual/util/util-macros-${version}.tar.gz" +tarball_blake2b="4c79c7076281ede6a240be2a2a9ffd47edd523d4a1b839589301a21eeb73100f134eced7d81fbd5ad71516174d3d4c8ab9f63e53987cb0f9a59b4fe6496157d8" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autoreconf -fvi +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-xclock b/recipes/xorg-xclock new file mode 100644 index 00000000000..1ddd738ffcf --- /dev/null +++ b/recipes/xorg-xclock @@ -0,0 +1,27 @@ +name=xorg-xclock +version=1.1.1 +revision=1 +tarball_url="https://xorg.freedesktop.org/archive/individual/app/xclock-${version}.tar.gz" +tarball_blake2b="4fd77b8f1f0962774dd0e6295f7482c05be8107e1606a9705ccd2864d2c9b37adda4a41a6704c6e1363edd2b7e704324799c4feaff39e218b326b66274b48187" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros gettext" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 libxaw libxft libxkbfile libxmu libxrender" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --with-appdefaultdir=/etc/X11/app-defaults \ + --disable-selective-werror + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-xeyes b/recipes/xorg-xeyes new file mode 100644 index 00000000000..bac153bb7f3 --- /dev/null +++ b/recipes/xorg-xeyes @@ -0,0 +1,26 @@ +name=xorg-xeyes +version=1.2.0 +revision=1 +tarball_url="https://xorg.freedesktop.org/archive/individual/app/xeyes-${version}.tar.gz" +tarball_blake2b="de152dff4bffb8ce43f7a8ae6b3362088f829acfa2a276b714cb5f92fb7af2935553f685a5cbe9d5f4362177fa71afc5b9e2aabe18010d247a16bad7892c8a7c" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 libxcb libxext libxi libxmu libxrender libxt" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --disable-selective-werror + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-xfontsel b/recipes/xorg-xfontsel new file mode 100644 index 00000000000..7ae92585b46 --- /dev/null +++ b/recipes/xorg-xfontsel @@ -0,0 +1,26 @@ +name=xorg-xfontsel +version=1.1.0 +revision=1 +tarball_url="https://www.x.org/pub/individual/app/xfontsel-${version}.tar.xz" +tarball_blake2b="e4cb8f25b64e1feb68cdf7ae7982c8e8e6086fb6ad31019b115986220cd9f347edbe738d8d43d0650fd783ef96d2e93a247e462611b0fb33a3aa0a6dc2d2529e" +source_hostdeps="autoconf automake libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxmu libxaw" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure \ + --with-appdefaultdir=/etc/X11/app-defaults + + make -j${parallelism} +} + +package() { + make DESTDIR=${dest_dir} install + + post_package_strip +} diff --git a/recipes/xorg-xinit b/recipes/xorg-xinit new file mode 100644 index 00000000000..5272d84a92b --- /dev/null +++ b/recipes/xorg-xinit @@ -0,0 +1,25 @@ +name=xorg-xinit +version=1.4.2 +tarball_url="https://gitlab.freedesktop.org/xorg/app/xinit/-/archive/xinit-${version}/xinit-xinit-${version}.tar.gz" +tarball_blake2b="23a48ddee9eab2510fc3322dc203a994f886b765f49c3c92c34b75ed871c844e860ae47581167d905ae59822a8e69fcd1b94e680db933aea251596286d19617b" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libx11 xorg-proto" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure +} + +package() { + DESTDIR="${dest_dir}" make install + + # We have our own xinitrc. + rm -rf "${dest_dir}/etc/X11/xinit/xinitrc" + + post_package_strip +} diff --git a/recipes/xorg-xkbcomp b/recipes/xorg-xkbcomp new file mode 100644 index 00000000000..aa44578f23c --- /dev/null +++ b/recipes/xorg-xkbcomp @@ -0,0 +1,25 @@ +name=xorg-xkbcomp +version=1.4.6 +revision=1 +tarball_url="https://www.x.org/archive/individual/app/xkbcomp-${version}.tar.gz" +tarball_blake2b="bc0fe69ef4eb809ac9e82fdc40b990bf27b7dd3e358efdb87ab7e34be8ddd0d8bd54e57ab7473f9e22f2714964e2cfb3322ccc2006a64de10dd6f2fc4fa35017" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxkbfile" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xorg-xlsfonts b/recipes/xorg-xlsfonts new file mode 100644 index 00000000000..8ec9a1452af --- /dev/null +++ b/recipes/xorg-xlsfonts @@ -0,0 +1,24 @@ +name=xorg-xlsfonts +version=1.0.7 +revision=1 +tarball_url="https://www.x.org/pub/individual/app/xlsfonts-${version}.tar.xz" +tarball_blake2b="13f2e2007c38f7d1724e6ffd0c7fe9a3b887a150f50107b892327c3620e4ffdbd4ae1191a9764cc4000d6422fe0f331dcbef11c0b50013ff2d94b699c0cba1ee" +source_hostdeps="autoconf automake libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs libxmu libxaw" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + make DESTDIR=${dest_dir} install + post_package_strip +} diff --git a/recipes/xtrans b/recipes/xtrans new file mode 100644 index 00000000000..18e4de6fa62 --- /dev/null +++ b/recipes/xtrans @@ -0,0 +1,25 @@ +name=xtrans +version=1.5.0 +revision=1 +tarball_url="https://www.x.org/archive/individual/lib/xtrans-${version}.tar.gz" +tarball_blake2b="25a18ba2398e445a1fedec3f0f5a102aef733b621fb83a81d193a2e4a702b8090b70ccea1c6784293050fd26b20e2d4b2d433954c9740c3a94c53362dc88cc9b" +source_hostdeps="automake autoconf libtool pkg-config" +source_deps="xorg-util-macros" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/xz b/recipes/xz new file mode 100644 index 00000000000..5cfdcce1766 --- /dev/null +++ b/recipes/xz @@ -0,0 +1,24 @@ +name=xz +version=5.4.5 +revision=1 +tarball_url="http://deb.debian.org/debian/pool/main/x/xz-utils/xz-utils_5.6.1+really5.4.5.orig.tar.xz" +tarball_blake2b="08d9afebd927ea5d155515a4c9eedda4d1a249f2b1ab6ada11f50e5b7a3c90b389b32378ab1c0872c7f4627de8dff37149d85e49f7f4d30614add37320ec4f3e" +source_hostdeps="automake autoconf libtool pkg-config" +hostdeps="gcc autoconf automake libtool pkg-config" +deps="core-libs" + +regenerate() { + autotools_recursive_regen +} + +build() { + autotools_configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + + post_package_strip +} diff --git a/recipes/zlib b/recipes/zlib new file mode 100644 index 00000000000..4591965f905 --- /dev/null +++ b/recipes/zlib @@ -0,0 +1,27 @@ +name=zlib +version=1.3 +revision=1 +tarball_url="https://github.com/madler/zlib/archive/refs/tags/v${version}.tar.gz" +tarball_blake2b="e663d8041a613b544d76313e61b6340adacb53322422d4b6392455627c80cbac430b9fd0fb4a69e59b0fa110f120d29a1e9513bb37888442cc1b9d5075f47ea6" +imagedeps="patchelf" +hostdeps="gcc pkg-config" +deps="core-libs" + +build() { + prefix="${prefix}" \ + CHOST="${OS_TRIPLET}" \ + ${source_dir}/configure + + make -j${parallelism} +} + +package() { + DESTDIR="${dest_dir}" make install + # Remove static libraries + rm -rf "${dest_dir}${prefix}"/lib/*.a + + # libz.so.${version} is created without soname... fix that + patchelf --set-soname libz.so.${version} "${dest_dir}${prefix}/lib/libz.so.${version}" + + post_package_strip +} diff --git a/recipes/zstd b/recipes/zstd new file mode 100644 index 00000000000..5633699c717 --- /dev/null +++ b/recipes/zstd @@ -0,0 +1,29 @@ +name=zstd +version=1.5.5 +revision=1 +tarball_url="https://github.com/facebook/zstd/releases/download/v${version}/zstd-${version}.tar.gz" +tarball_blake2b="7680e27a0adacfb809d9fc81e06d3f99bf74df30374d3b5cb2d58f667dd1b7d5c41697e608592709e17c0e32277f20a6d615edee409b5d7cdcb15da2799a2350" +hostdeps="gcc pkg-config" +deps="core-libs zlib xz" + +build() { + cp -rp "${source_dir}"/. ./ + + CC=${OS_TRIPLET}-gcc \ + CXX=${OS_TRIPLET}-g++ \ + AR=${OS_TRIPLET}-ar \ + PREFIX="${prefix}" \ + make -j${parallelism} +} + +package() { + CC=${OS_TRIPLET}-gcc \ + DESTDIR="${dest_dir}" \ + PREFIX="${prefix}" \ + make install + + # Remove static libraries. + rm -rf "${dest_dir}${prefix}"/lib/*.a + + post_package_strip +} diff --git a/scripts/mkimage b/scripts/mkimage new file mode 100755 index 00000000000..985c735ae2a --- /dev/null +++ b/scripts/mkimage @@ -0,0 +1,48 @@ +# set -x -e + +# IMAGE_PATH="$base_dir/target/disk.img" +# LOOPBACK_DEV_PATH="$base_dir/target/loopback_dev" + +# ls /dev + +# # echo $in_container +# # whoami + +# # # ls $base_dir + +IMAGE_PATH="./target/disk.img" + +dd if=/dev/zero bs=1G count=0 seek=512 of=$IMAGE_PATH +parted -s $IMAGE_PATH mklabel gpt +parted -s $IMAGE_PATH mkpart primary 2048s 100% + +# # # ensure loop kernel module is enabled +# # if ! lsmod | grep -q 'loop'; then +# # echo 'mkimage: `loop` kernel module not found, attempting to load' +# # modprobe loop +# # fi + +# # losetup -Pf --show $IMAGE_PATH > $LOOPBACK_DEV_PATH +# # losetup -d `cat $LOOPBACK_DEV_PATH` + +# # # echo $in_container +# # # ls /de + +# -L: volume-label +# -N: Overrides the default calculation of the number of inodes that should be reserved for the filesystem. +# -O: Features (disabled are prefixed with `^`) +# -d: root-directory +# -m: reserved-blocks-percentage +# -r: fs-revision-level +# # -t: filesystem-type +# mke2fs \ +# -L '' \ +# -N 0 \ +# -O ^64bit \ +# -d "./sysroot" \ +# -m 5 \ +# -r 1 \ +# -t ext2 \ +# "./target/disk.img" \ +# 5G \ +# ; diff --git a/source-recipes/autoconf b/source-recipes/autoconf new file mode 100644 index 00000000000..09be1b2004c --- /dev/null +++ b/source-recipes/autoconf @@ -0,0 +1,4 @@ +name=autoconf +version=2.72 +tarball_url="https://ftp.gnu.org/gnu/autoconf/autoconf-${version}.tar.gz" +tarball_blake2b="48fff54704176cbf2642230229c628b75c43ef3f810c39eea40cae91dd02e1203d04a544407de96f9172419a94b952865909d969d9e9b6c10879a9d9aeea5ad0" diff --git a/source-recipes/autoconf-2.69 b/source-recipes/autoconf-2.69 new file mode 100644 index 00000000000..3986c79acb4 --- /dev/null +++ b/source-recipes/autoconf-2.69 @@ -0,0 +1,4 @@ +name=autoconf-2.69 +version=2.69 +tarball_url="https://ftp.gnu.org/gnu/autoconf/autoconf-${version}.tar.gz" +tarball_blake2b="7e8a513bbfcabadad1577919c048cc05ca0a084788850b42570f88afc2fa9c25fb32277412f135b81ba1c0d8079465a6b581d2d78662c991d2183b739fac407c" diff --git a/source-recipes/automake b/source-recipes/automake new file mode 100644 index 00000000000..0c58eb68b0c --- /dev/null +++ b/source-recipes/automake @@ -0,0 +1,8 @@ +name=automake +version=1.16.5 +tarball_url="https://ftp.gnu.org/gnu/automake/automake-${version}.tar.gz" +tarball_blake2b="5ccdcbe2d3deb2b0baed4a8590b07714cd7098fbda251afebe83232ed03f4db84abbe023cf0544622dbc5137254347273247428eb5420564a167b86de95d113e" + +regenerate() { + true +} diff --git a/source-recipes/cmake b/source-recipes/cmake new file mode 100644 index 00000000000..1821d68b1a2 --- /dev/null +++ b/source-recipes/cmake @@ -0,0 +1,4 @@ +name=cmake +version=3.27.7 +tarball_url="https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}.tar.gz" +tarball_blake2b="a20fac503ba54b4b7e85896056a614b67aa346ad2636e7ab1bf09a2660b92a52754485527f36101e59d47713e7445d27797577c1fa6a8ebe59acb4675227c6da" diff --git a/source-recipes/gcc-host b/source-recipes/gcc-host new file mode 100644 index 00000000000..38d73211c97 --- /dev/null +++ b/source-recipes/gcc-host @@ -0,0 +1,16 @@ +name=gcc-host +version=13.2.0 +tarball_url="https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz" +tarball_blake2b="0034b29d3d6cc05821f0c4253ce077805943aff7b370729dd203bda57d89c107edd657eeddc2fb1e69ea15c7b0323b961f46516c7f4af89a3ccf7fea84701be2" +hostdeps="automake autoconf-2.69 libtool pkg-config" +imagedeps="git" +allow_network="yes" + +regenerate() { + ./contrib/download_prerequisites + + autotools_recursive_regen -I"$(realpath ./config)" + + cp -pv /usr/local/share/libtool/build-aux/{config.sub,config.guess,install-sh} libiberty/ + cp -pv /usr/local/share/libtool/build-aux/{config.sub,config.guess,install-sh} libgcc/ +} diff --git a/source-recipes/gnulib b/source-recipes/gnulib new file mode 100644 index 00000000000..623e07de9e4 --- /dev/null +++ b/source-recipes/gnulib @@ -0,0 +1,4 @@ +name=gnulib +version=4f6545e79c4a7cd7feb2c8f23f1d5167e7165907 +tarball_url="https://git.savannah.gnu.org/cgit/gnulib.git/snapshot/gnulib-${version}.tar.gz" +tarball_blake2b="0206d3bdeb25bdc3562065dc1832d3ea2ac95920b84ed0461626efba83de3edfcdcbc257c493a9a3d6035d0edb09526248c2483f898110be774ac31caf650e58" diff --git a/source-recipes/intltool b/source-recipes/intltool new file mode 100644 index 00000000000..b0682a9ac59 --- /dev/null +++ b/source-recipes/intltool @@ -0,0 +1,9 @@ +name=intltool +version=0.51.0 +tarball_url="https://launchpad.net/intltool/trunk/${version}/+download/intltool-${version}.tar.gz" +tarball_blake2b="98fe40e4d669fdf65a777152ddee0a9656412b9cf5d1e682d1b4b7bd666f3e5aa623a50481b6df47e16a935550836c66c666229b0bb7ef143f7cde6893b97a69" +hostdeps="autoconf automake libtool pkg-config" + +regenerate() { + autotools_recursive_regen +} diff --git a/source-recipes/libgcc-binaries b/source-recipes/libgcc-binaries new file mode 100644 index 00000000000..749340993f1 --- /dev/null +++ b/source-recipes/libgcc-binaries @@ -0,0 +1,4 @@ +name=libgcc-binaries +version=1e4b24ef15a7d9a2db7570d1c9283fc474dcbd73 +tarball_url="https://github.com/mintsuki/libgcc-binaries/archive/${version}.tar.gz" +tarball_blake2b="77b8af0466577ca5af9b16d968865d24d42fb422566de2f03dd5b2d984f70015da6b1bd28878855889ee665f0ace4419cee3c40d20ac1176b0c500a1e50302bd" diff --git a/source-recipes/libtool b/source-recipes/libtool new file mode 100644 index 00000000000..c5d13fc2df2 --- /dev/null +++ b/source-recipes/libtool @@ -0,0 +1,11 @@ +name=libtool +version=2.4.7 +tarball_url="https://ftp.gnu.org/gnu/libtool/libtool-${version}.tar.gz" +tarball_blake2b="3b7c66050237931443008d6be9c0c30f4938402bf68576cdf02f2248b216bb68c6b797bbfdb8a92caa5e12cb10208cd19771cdcb6b0d83572ad60bfc03e67e98" +hostdeps="autoconf automake gnulib" +imagedeps="help2man" + +regenerate() { + cp -r ${base_dir}/sources/gnulib ./ + ./bootstrap --force --skip-git --skip-po --gnulib-srcdir=`pwd`/gnulib +} diff --git a/source-recipes/limine b/source-recipes/limine new file mode 100644 index 00000000000..8f96cc8e020 --- /dev/null +++ b/source-recipes/limine @@ -0,0 +1,12 @@ +name=limine +version=7.0.0 +revision=1 +tarball_url="https://github.com/limine-bootloader/limine/releases/download/v${version}/limine-${version}.tar.xz" +tarball_blake2b="7986d948fe84c80b338e5cc66edca5f511d277d2e854484c87183666bf1b075480b61213c177b6e39a1145502cc9e07b9e1442c3dcf3171339af5b55ac9c184f" +hostdeps="gcc libtool pkg-config autoconf automake" +deps="core-libs" +imagedeps="mtools nasm" + +regenerate() { + autoreconf -fvi +} \ No newline at end of file diff --git a/source-recipes/llvm-host b/source-recipes/llvm-host new file mode 100644 index 00000000000..af821a6152f --- /dev/null +++ b/source-recipes/llvm-host @@ -0,0 +1,11 @@ +name=llvm-host +version=17.0.6 +tarball_url="https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-project-${version}.src.tar.xz" +tarball_blake2b="d6ede1a9fda8756995c3e0654111941649e15794179641806f18919f1dc68c41ca0cabd5693b5096d05dccc3a391cd20d34af1137bf8af92ed3117a1ce84d1b2" + +regenerate() { + echo "Regenerating LLVM..." + for i in "${base_dir}"/patches/llvm/*; do + patch -p1 < "$i" + done +} diff --git a/source-recipes/pkg-config b/source-recipes/pkg-config new file mode 100644 index 00000000000..1195750a296 --- /dev/null +++ b/source-recipes/pkg-config @@ -0,0 +1,9 @@ +name=pkg-config +version=2.1.0 +tarball_url="https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-${version}.tar.gz" +tarball_blake2b="ab0f03494c37659c18a882ff03e6bb746c3cfe0ad66b7a9d9d0b2de66bec89258b2374addd3eb3a571442d8bab3c1311410e296379b697d16aaebe2bc89b318c" +hostdeps="autoconf automake libtool" + +regenerate() { + autoreconf -fvi +} diff --git a/source-recipes/rust-host b/source-recipes/rust-host new file mode 100644 index 00000000000..80122e1c151 --- /dev/null +++ b/source-recipes/rust-host @@ -0,0 +1,33 @@ +name=rust-host +version=1.75.0 +tarball_url="https://static.rust-lang.org/dist/rustc-${version}-src.tar.xz" +tarball_blake2b="8937b80585eddaa3e1f1ef948899d14a170308518c6fef9fe569560cdd870053776956743f796055f2119399b9ca6c0df12fedd789ae46324d071e5126c4e495" + +regenerate() { + cat > ${source_dir}/config.toml <. - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use std::fs; @@ -24,7 +22,7 @@ use std::ffi::OsString; use std::fs::DirEntry; use std::path::Path; -//this is all magic, yes dont ever let anyone see this shit +// this is all magic, yes dont ever let anyone see this shit /// Helper function of walking the provided `dir`, only visiting files and calling /// `cb` on each file. @@ -63,7 +61,7 @@ fn main() -> Result<(), Box> { Some(ext) if ext.eq(&OsString::from("inc")) => { let path = path .to_str() - .expect("invalud UTF-8 for file path (skill issue)"); + .expect("invalid UTF-8 for file path (skill issue)"); inc_files.push(path.to_string()) } @@ -75,8 +73,8 @@ fn main() -> Result<(), Box> { inc_files = inc_files .iter() .map(|e| { - let e = e.split("/").collect::>(); - e[..e.len() - 1].join("/").to_string() + let e = e.split('/').collect::>(); + e[..e.len() - 1].join("/") }) .collect::>(); @@ -115,6 +113,9 @@ fn main() -> Result<(), Box> { } })?; + // Tell cargo to pass the linker script to the linker.. + println!("cargo:rustc-link-arg=-T.cargo/kernel.ld"); + // ..and to re-run if it changes. println!("cargo:rerun-if-changed=.cargo/kernel.ld"); Ok(()) diff --git a/src/aero_kernel/src/acpi/aml.rs b/src/aero_kernel/src/acpi/aml.rs index 280be84b4cc..60992e06d86 100644 --- a/src/aero_kernel/src/acpi/aml.rs +++ b/src/aero_kernel/src/acpi/aml.rs @@ -17,6 +17,7 @@ pub trait AmlSubsystem: Send + Sync { /// ## Parameters /// * `mode` - IRQ mode (ACPI spec section 5.8.1) fn enable_acpi(&self, mode: u32); + fn pci_route_pin(&self, seg: u16, bus: u8, slot: u8, function: u8, pin: u8) -> u8; } static AML_SUBSYSTEM: Once> = Once::new(); diff --git a/src/aero_kernel/src/acpi/fadt.rs b/src/aero_kernel/src/acpi/fadt.rs index 31e682225b4..7f77f57100e 100644 --- a/src/aero_kernel/src/acpi/fadt.rs +++ b/src/aero_kernel/src/acpi/fadt.rs @@ -1,23 +1,22 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . -//! The FADT ACPI table contains information about fixed register blocks pertaining to power management. +//! The FADT ACPI table contains information about fixed register blocks pertaining to power +//! management. //! //! **Notes**: @@ -34,7 +33,7 @@ pub struct Fadt { // Field used in ACPI 1.0; no longer in use, for compatibility only reserved: u8, - pub preferred_power_managament: u8, + pub preferred_power_management: u8, pub sci_interrupt: u16, pub smi_command_port: u32, pub acpi_enable: u8, diff --git a/src/aero_kernel/src/acpi/hpet.rs b/src/aero_kernel/src/acpi/hpet.rs index 9da7751f1ae..af50003ff27 100644 --- a/src/aero_kernel/src/acpi/hpet.rs +++ b/src/aero_kernel/src/acpi/hpet.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::ptr; @@ -38,8 +36,6 @@ pub(super) struct Hpet { impl Hpet { pub fn new(sdt: &'static Sdt) -> Self { - let this = unsafe { ptr::read((sdt as *const Sdt) as *const Self) }; - - this + unsafe { ptr::read((sdt as *const Sdt) as *const Self) } } } diff --git a/src/aero_kernel/src/acpi/madt.rs b/src/aero_kernel/src/acpi/madt.rs index 6a5326207e2..6ced67daed6 100644 --- a/src/aero_kernel/src/acpi/madt.rs +++ b/src/aero_kernel/src/acpi/madt.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::mem; @@ -108,14 +106,14 @@ impl Iterator for MadtIterator { while self.current < self.limit { unsafe { let entry_pointer = self.current; - let header = *(self.current as *const EntryHeader); + let header = *self.current.cast::(); self.current = self.current.offset(header.length as isize); let item = match header.entry_type { - 0 => MadtEntry::LocalApic(&*(entry_pointer as *const MadtLocalApic)), - 1 => MadtEntry::IoApic(&*(entry_pointer as *const IoApicHeader)), - 2 => MadtEntry::IntSrcOverride(&*(entry_pointer as *const MadtIntSrcOverride)), + 0 => MadtEntry::LocalApic(&*entry_pointer.cast::()), + 1 => MadtEntry::IoApic(&*entry_pointer.cast::()), + 2 => MadtEntry::IntSrcOverride(&*entry_pointer.cast::()), 0x10..=0x7f => continue, 0x80..=0xff => continue, diff --git a/src/aero_kernel/src/acpi/mcfg.rs b/src/aero_kernel/src/acpi/mcfg.rs index 53140d9e331..d24508260a8 100644 --- a/src/aero_kernel/src/acpi/mcfg.rs +++ b/src/aero_kernel/src/acpi/mcfg.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::mem; @@ -57,7 +55,7 @@ impl Mcfg { /// /// ## Notes /// Returns false if called before the ACPI tables were initialized. -pub fn is_avaliable() -> bool { +pub fn is_available() -> bool { MCFG.get().is_some() } diff --git a/src/aero_kernel/src/acpi/mod.rs b/src/aero_kernel/src/acpi/mod.rs index a6a97e2dd77..f7f59d19708 100644 --- a/src/aero_kernel/src/acpi/mod.rs +++ b/src/aero_kernel/src/acpi/mod.rs @@ -1,35 +1,34 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! The ACPI (Advanced Configuration and Power Interface) tables help to gather the -//! CPU, interrupt, and timer informations. +//! CPU, interrupt, and timer information. //! //! **Notes**: use spin::Once; -use crate::{ - mem::paging::VirtAddr, - utils::sync::{Mutex, MutexGuard}, -}; +use crate::mem::paging::VirtAddr; +use crate::utils::sync::{Mutex, MutexGuard}; -use self::{hpet::Hpet, madt::Madt, mcfg::Mcfg, sdt::Sdt}; +use self::hpet::Hpet; +use self::madt::Madt; +use self::mcfg::Mcfg; +use self::sdt::Sdt; pub mod aml; pub mod fadt; @@ -72,10 +71,10 @@ impl AcpiTable { } /// Lookup ACPI table entry with the provided signature. - pub fn lookup_entry(&self, signature: &str) -> Option<&'static Sdt> { + pub fn lookup_entry(&self, signature: &str, index: usize) -> Option<&'static Sdt> { match self.header { - AcpiHeader::Rsdt(rsdt) => rsdt.lookup_entry(signature), - AcpiHeader::Xsdt(xsdt) => xsdt.lookup_entry(signature), + AcpiHeader::Rsdt(rsdt) => rsdt.lookup_entry(signature, index), + AcpiHeader::Xsdt(xsdt) => xsdt.lookup_entry(signature, index), } } @@ -87,7 +86,7 @@ impl AcpiTable { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct GenericAddressStructure { pub address_space: u8, @@ -112,19 +111,19 @@ pub fn init(rsdp_address: VirtAddr) { let acpi_table = get_acpi_table(); macro init_table($sig:path => $ty:ty) { - if let Some(table) = acpi_table.lookup_entry($sig) { + if let Some(table) = acpi_table.lookup_entry($sig, 0) { <$ty>::new(table); } } - if let Some(header) = acpi_table.lookup_entry(mcfg::SIGNATURE) { + if let Some(header) = acpi_table.lookup_entry(mcfg::SIGNATURE, 0) { unsafe { let mcfg: &'static Mcfg = header.as_ref(); mcfg.init(); } } - if let Some(header) = acpi_table.lookup_entry(madt::SIGNATURE) { + if let Some(header) = acpi_table.lookup_entry(madt::SIGNATURE, 0) { unsafe { // Not a valid MADT table without the local apic address and the flags. if header.data_len() < 8 { diff --git a/src/aero_kernel/src/acpi/rsdp.rs b/src/aero_kernel/src/acpi/rsdp.rs index 1bdb437b3be..008282bc90b 100644 --- a/src/aero_kernel/src/acpi/rsdp.rs +++ b/src/aero_kernel/src/acpi/rsdp.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::marker::PhantomData; @@ -41,21 +39,10 @@ pub(super) unsafe fn validate_checksum(ptr: *const u8, size: usize) -> bool { sum == 0 } -pub(super) trait RsdtTyp { - fn as_usize(self) -> usize; -} - -impl RsdtTyp for u32 { - fn as_usize(self) -> usize { - self as _ - } -} +pub(super) trait RsdtTyp {} -impl RsdtTyp for u64 { - fn as_usize(self) -> usize { - self as _ - } -} +impl RsdtTyp for u32 {} +impl RsdtTyp for u64 {} pub(super) trait RsdtHeader { fn signature(&self) -> &[u8]; @@ -105,7 +92,7 @@ pub(super) struct Rsdt { impl Rsdt { pub fn new(address: VirtAddr) -> &'static Self { - let this = unsafe { &*(address.as_ptr() as *const Self) }; + let this = unsafe { &*address.as_ptr::() }; let valid_checksum = this.header.is_valid(); let valid_signature = this.header.signature() == b"RSDT"; @@ -120,18 +107,23 @@ impl Rsdt { (self.header.length as usize - core::mem::size_of::()) / core::mem::size_of::() } - pub fn lookup_entry(&self, signature: &str) -> Option<&'static Sdt> { + pub fn lookup_entry(&self, signature: &str, index: usize) -> Option<&'static Sdt> { + let mut current = 0; let header_data_address = self.header.data_address() as *const u32; for i in 0..self.entries_count() { let item_addr_virt = unsafe { let ptr = header_data_address.add(i); - PhysAddr::new(*ptr as u64).as_hhdm_virt() + PhysAddr::new(ptr.read_unaligned() as u64).as_hhdm_virt() }; let item = unsafe { Sdt::from_address(item_addr_virt) }; if item.signature == signature.as_bytes() { - return Some(item); + if current == index { + return Some(item); + } + + current += 1; } } @@ -141,7 +133,7 @@ impl Rsdt { impl Rsdt { pub fn new(address: VirtAddr) -> &'static Self { - let this = unsafe { &*(address.as_ptr() as *const Self) }; + let this = unsafe { &*address.as_ptr::() }; let valid_checksum = this.header.is_valid(); let valid_signature = this.header.signature() == b"XSDT"; @@ -156,7 +148,8 @@ impl Rsdt { (self.header.length as usize - core::mem::size_of::()) / core::mem::size_of::() } - pub fn lookup_entry(&self, signature: &str) -> Option<&'static Sdt> { + pub fn lookup_entry(&self, signature: &str, index: usize) -> Option<&'static Sdt> { + let mut current = 0; let header_data_address = self.header.data_address() as *const u64; for i in 0..self.entries_count() { @@ -168,7 +161,11 @@ impl Rsdt { let item = unsafe { Sdt::from_address(item_addr_virt) }; if item.signature == signature.as_bytes() { - return Some(item); + if current == index { + return Some(item); + } + + current += 1; } } @@ -183,7 +180,7 @@ pub(super) enum RsdtAddress { pub(super) fn find_rsdt_address(rsdp_address: VirtAddr) -> RsdtAddress { // Look for RSDP v2 header, and if it does not exists, look for RSDP v1 header. - let v20 = unsafe { &*(rsdp_address.as_ptr() as *const Rsdp20) }; + let v20 = unsafe { &*rsdp_address.as_ptr::() }; let is_v20 = v20.revision >= 2 && v20.xsdt_address != 0; if is_v20 { @@ -191,14 +188,14 @@ pub(super) fn find_rsdt_address(rsdp_address: VirtAddr) -> RsdtAddress { assert!(valid, "rsdp: failed to validate RSDP v20 checksum"); let xsdt_address = PhysAddr::new(v20.xsdt_address).as_hhdm_virt(); - return RsdtAddress::Xsdt(xsdt_address); + RsdtAddress::Xsdt(xsdt_address) } else { - let v10 = unsafe { &*(rsdp_address.as_ptr() as *const Rsdp10) }; + let v10 = unsafe { &*rsdp_address.as_ptr::() }; let valid = validate_rsdt_checksum(v10); assert!(valid, "rsdp: failed to validate RSDP v10 checksum"); let rsdt_address = PhysAddr::new(v10.rsdt_address as u64).as_hhdm_virt(); - return RsdtAddress::Rsdt(rsdt_address); + RsdtAddress::Rsdt(rsdt_address) } } diff --git a/src/aero_kernel/src/acpi/sdt.rs b/src/aero_kernel/src/acpi/sdt.rs index 3589cf115cd..8d1c9292314 100644 --- a/src/aero_kernel/src/acpi/sdt.rs +++ b/src/aero_kernel/src/acpi/sdt.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::mem; diff --git a/src/aero_kernel/src/arch/aarch64/mod.rs b/src/aero_kernel/src/arch/aarch64/mod.rs index 36aa7e20a64..0a9d9c9f31c 100644 --- a/src/aero_kernel/src/arch/aarch64/mod.rs +++ b/src/aero_kernel/src/arch/aarch64/mod.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . pub mod dtb; pub mod interrupts; @@ -55,7 +53,7 @@ extern "C" fn arch_aero_main() -> ! { .expect("limine: invalid kernel file pointer"); // Before we start the initialization process, we need to make sure - // the unwind info is avaliable; just in case if there is a kernel + // the unwind info is available; just in case if there is a kernel // panic, it will be able to unwind the stack. crate::unwind::UNWIND_INFO.call_once(|| { use crate::unwind::UnwindInfo; @@ -75,7 +73,7 @@ extern "C" fn arch_aero_main() -> ! { // Now that we have unwind info, we can initialize the COM ports. This // will be used to print panic messages/logs before the debug renderer is - // initialized to the serial output (if avaliable). + // initialized to the serial output (if available). drivers::uart::init(); logger::init(); diff --git a/src/aero_kernel/src/arch/aarch64/task.rs b/src/aero_kernel/src/arch/aarch64/task.rs index 2a319d45112..fc0c5247f53 100644 --- a/src/aero_kernel/src/arch/aarch64/task.rs +++ b/src/aero_kernel/src/arch/aarch64/task.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use crate::fs::cache::DirCacheItem; use crate::mem::paging::*; diff --git a/src/aero_kernel/src/arch/aarch64/time.rs b/src/aero_kernel/src/arch/aarch64/time.rs index c8db1f49de3..950bfc34fd3 100644 --- a/src/aero_kernel/src/arch/aarch64/time.rs +++ b/src/aero_kernel/src/arch/aarch64/time.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use aero_syscall::TimeSpec; diff --git a/src/aero_kernel/src/arch/aarch64/tls.rs b/src/aero_kernel/src/arch/aarch64/tls.rs index 87940d1f913..68b8a48b63a 100644 --- a/src/aero_kernel/src/arch/aarch64/tls.rs +++ b/src/aero_kernel/src/arch/aarch64/tls.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . pub fn get_cpuid() -> usize { unimplemented!() diff --git a/src/aero_kernel/src/arch/mod.rs b/src/aero_kernel/src/arch/mod.rs index e529a4f3978..d218c34ae03 100644 --- a/src/aero_kernel/src/arch/mod.rs +++ b/src/aero_kernel/src/arch/mod.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #[cfg(target_arch = "x86_64")] mod x86_64; diff --git a/src/aero_kernel/src/arch/x86_64/apic.rs b/src/aero_kernel/src/arch/x86_64/apic.rs index bf05d776cce..eca596b90c7 100644 --- a/src/aero_kernel/src/arch/x86_64/apic.rs +++ b/src/aero_kernel/src/arch/x86_64/apic.rs @@ -1,27 +1,25 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::ptr; use core::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}; +use crate::arch::interrupts; use crate::arch::interrupts::InterruptStack; -use crate::arch::{interrupts, tls}; use crate::mem::paging::{PhysAddr, VirtAddr}; use raw_cpuid::{CpuId, FeatureInfo}; use spin::Once; @@ -31,7 +29,6 @@ use crate::utils::sync::{Mutex, MutexGuard}; use super::{io, time}; use crate::acpi::madt; -use crate::PHYSICAL_MEMORY_OFFSET; const APIC_SPURIOUS_VECTOR: u32 = 0xFF; @@ -110,6 +107,9 @@ fn lapic_error_handler(_stack: &mut InterruptStack) { log::error!("ESR={:#0x}", self::get_local_apic().get_esr()); } +#[cpu_local] +static mut LAPIC_TIMER_FREQUENCY: u32 = 0; + pub struct LocalApic { address: VirtAddr, apic_type: ApicType, @@ -118,7 +118,7 @@ pub struct LocalApic { impl LocalApic { /// Creates a new local APIC instance. /// - /// ## Saftey + /// ## Safety /// The provided `address` points to a valid local APIC memory region and /// the `apic_type` is valid. fn new(address: VirtAddr, apic_type: ApicType) -> Self { @@ -196,7 +196,7 @@ impl LocalApic { pub fn timer_oneshot(&mut self, vec: u8, us: usize) { self.timer_stop(); - let lapic_timer_frequency = tls::get_percpu().lapic_timer_frequency; + let lapic_timer_frequency = unsafe { *LAPIC_TIMER_FREQUENCY }; let ticks = us * (lapic_timer_frequency / 1000000) as usize; unsafe { @@ -227,7 +227,7 @@ impl LocalApic { let pit_ticks = initial_pit_tick - final_pit_tick; let timer_frequency = (SAMPLES / pit_ticks as u32) * time::PIT_DIVIDEND as u32; - tls::get_percpu().lapic_timer_frequency = timer_frequency; + *LAPIC_TIMER_FREQUENCY = timer_frequency; } self.timer_stop(); @@ -288,11 +288,11 @@ impl LocalApic { /// This function works for both XAPIC and X2APIC. /// /// ## Safety - /// * The provided `register` must be a valid APIC register and the `value` must - /// be a valid value for the provided APIC register. + /// * The provided `register` must be a valid APIC register and the `value` must be a valid + /// value for the provided APIC register. /// - /// * If the `register` is 64-bit wide, then the [`Self::write_long`] function must - /// be used instead. + /// * If the `register` is 64-bit wide, then the [`Self::write_long`] function must be used + /// instead. unsafe fn write(&mut self, register: u32, value: u32) { match self.apic_type { ApicType::X2apic => { @@ -385,12 +385,12 @@ pub fn io_apic_set_redirect(vec: u8, gsi: u32, flags: u16, status: i32) { let mut redirect = 0x00; // Active high(0) or low(1) - if flags & 2 == 1 { + if (flags & (1 << 1)) != 0 { redirect |= (1 << 13) as u8; } // Edge(0) or level(1) triggered - if flags & 8 == 1 { + if (flags & (1 << 3)) != 0 { redirect |= (1 << 15) as u8; } @@ -406,7 +406,7 @@ pub fn io_apic_set_redirect(vec: u8, gsi: u32, flags: u16, status: i32) { let ioredtbl = (gsi - entry.global_system_interrupt_base) * 2 + 16; unsafe { - io_apic_write(io_apic, ioredtbl + 0, redirect as _); + io_apic_write(io_apic, ioredtbl, redirect as _); io_apic_write(io_apic, ioredtbl + 1, (redirect as u64 >> 32) as _); } @@ -449,7 +449,7 @@ pub fn init() -> ApicType { log::debug!("apic: detected APIC (addr={address_phys:?}, type={apic_type:?})"); - let address_virt = unsafe { PHYSICAL_MEMORY_OFFSET } + address_phys.as_u64(); + let address_virt = address_phys.as_hhdm_virt(); let mut local_apic = LocalApic::new(address_virt, apic_type); local_apic.init(); @@ -470,5 +470,5 @@ pub fn init() -> ApicType { INTERRUPT_CONTROLLER.switch_to_apic(); } - return apic_type; + apic_type } diff --git a/src/aero_kernel/src/arch/x86_64/asm_macros.rs b/src/aero_kernel/src/arch/x86_64/asm_macros.rs new file mode 100644 index 00000000000..21c986e52b5 --- /dev/null +++ b/src/aero_kernel/src/arch/x86_64/asm_macros.rs @@ -0,0 +1,48 @@ +pub macro pop_preserved() { + " + pop r15 + pop r14 + pop r13 + pop r12 + pop rbp + pop rbx + " +} + +pub macro pop_scratch() { + " + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rdx + pop rcx + pop rax + " +} + +pub macro push_scratch() { + " + push rcx + push rdx + push rdi + push rsi + push r8 + push r9 + push r10 + push r11 + " +} + +pub macro push_preserved() { + " + push rbx + push rbp + push r12 + push r13 + push r14 + push r15 + " +} diff --git a/src/aero_kernel/src/arch/x86_64/controlregs.rs b/src/aero_kernel/src/arch/x86_64/controlregs.rs index d8663b1bd86..204a7fc9861 100644 --- a/src/aero_kernel/src/arch/x86_64/controlregs.rs +++ b/src/aero_kernel/src/arch/x86_64/controlregs.rs @@ -1,26 +1,26 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use crate::mem::paging::{PhysAddr, PhysFrame, VirtAddr}; bitflags::bitflags! { /// Controls cache settings for the level 4 page table. + #[derive(Debug, Copy, Clone)] + #[repr(transparent)] pub struct Cr3Flags: u64 { /// Use a writethrough cache policy for the P4 table (else a writeback policy is used). const PAGE_LEVEL_WRITETHROUGH = 1 << 3; @@ -31,6 +31,8 @@ bitflags::bitflags! { bitflags::bitflags! { /// Controls cache settings for the level 4 page table. + #[derive(Debug, Copy, Clone)] + #[repr(transparent)] pub struct Cr4Flags: u64 { /// Enables hardware-supported performance enhancements for software running in /// virtual-8086 mode. @@ -73,7 +75,7 @@ bitflags::bitflags! { const FSGSBASE = 1 << 16; /// Enables process-context identifiers (PCIDs). const PCID = 1 << 17; - /// Enables extendet processor state management instructions, including XGETBV and XSAVE. + /// Enables extended processor state management instructions, including XGETBV and XSAVE. const OSXSAVE = 1 << 18; /// Prevents the execution of instructions that reside in pages accessible by user-mode /// software when the processor is in supervisor-mode. @@ -88,6 +90,8 @@ bitflags::bitflags! { bitflags::bitflags! { /// Configuration flags of the [`Cr0`] register. + #[derive(Debug, Copy, Clone)] + #[repr(transparent)] pub struct Cr0Flags: u64 { /// Enables protected mode. const PROTECTED_MODE_ENABLE = 1; @@ -149,7 +153,7 @@ bitflags::bitflags! { const ALIGNMENT_CHECK = 1 << 18; /// Enable the virtual-8086 mode. const VIRTUAL_8086_MODE = 1 << 17; - /// Allows to restart an instruction following an instrucion breakpoint. + /// Allows to restart an instruction following an instruction breakpoint. const RESUME_FLAG = 1 << 16; /// Used by `iret` in hardware task switch mode to determine if current task is nested. const NESTED_TASK = 1 << 14; @@ -185,6 +189,75 @@ bitflags::bitflags! { } } +bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] + pub struct MxCsr: u32 { + const INVALID_OPERATION = 1 << 0; + const DENORMAL = 1 << 1; + const DIVIDE_BY_ZERO = 1 << 2; + const OVERFLOW = 1 << 3; + const UNDERFLOW = 1 << 4; + const PRECISION = 1 << 5; + const DENORMALS_ARE_ZEROS = 1 << 6; + const INVALID_OPERATION_MASK = 1 << 7; + const DENORMAL_MASK = 1 << 8; + const DIVIDE_BY_ZERO_MASK = 1 << 9; + const OVERFLOW_MASK = 1 << 10; + const UNDERFLOW_MASK = 1 << 11; + const PRECISION_MASK = 1 << 12; + const ROUNDING_CONTROL_NEGATIVE = 1 << 13; + const ROUNDING_CONTROL_POSITIVE = 1 << 14; + const ROUNDING_CONTROL_ZERO = 3 << 13; + const FLUSH_TO_ZERO = 1 << 15; + } +} + +bitflags::bitflags! { + /// Configuration flags of the XCr0 register. + /// + /// For MPX, [`BNDREG`](XCr0Flags::BNDREG) and [`BNDCSR`](XCr0Flags::BNDCSR) must be set/unset simultaneously. + /// For AVX-512, [`OPMASK`](XCr0Flags::OPMASK), [`ZMM_HI256`](XCr0Flags::ZMM_HI256), and [`HI16_ZMM`](XCr0Flags::HI16_ZMM) + /// must be set/unset simultaneously. + #[derive(Debug, Copy, Clone)] + #[repr(transparent)] + pub struct XCr0Flags: u64 { + /// Enables using the x87 FPU state + /// with `XSAVE`/`XRSTOR`. + /// + /// Must be set. + const X87 = 1; + /// Enables using MXCSR and the XMM registers + /// with `XSAVE`/`XRSTOR`. + /// + /// Must be set if [`AVX`](XCr0Flags::AVX) is set. + const SSE = 1 << 1; + /// Enables AVX instructions and using the upper halves of the AVX registers + /// with `XSAVE`/`XRSTOR`. + const AVX = 1 << 2; + /// Enables MPX instructions and using the BND0-BND3 bound registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const BNDREG = 1 << 3; + /// Enables MPX instructions and using the BNDCFGU and BNDSTATUS registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const BNDCSR = 1 << 4; + /// Enables AVX-512 instructions and using the K0-K7 mask registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const OPMASK = 1 << 5; + /// Enables AVX-512 instructions and using the upper halves of the lower ZMM registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const ZMM_HI256 = 1 << 6; + /// Enables AVX-512 instructions and using the upper ZMM registers + /// with `XSAVE`/`XRSTOR` (Intel Only). + const HI16_ZMM = 1 << 7; + /// Enables using the PKRU register + /// with `XSAVE`/`XRSTOR`. + const MPK = 1 << 9; + /// Enables Lightweight Profiling extensions and managing LWP state + /// with `XSAVE`/`XRSTOR` (AMD Only). + const LWP = 1 << 62; + } +} + /// Returns the current value of the RFLAGS register. pub fn read_rflags() -> RFlags { let value: u64; @@ -230,12 +303,40 @@ pub fn read_cr0() -> Cr0Flags { Cr0Flags::from_bits_truncate(value) // Get the flags from the bits. } +pub fn read_xcr0() -> XCr0Flags { + let (low, high): (u32, u32); + + unsafe { + asm!( + "xgetbv", + in("ecx") 0, + out("rax") low, out("rdx") high, + options(nomem, nostack, preserves_flags), + ); + } + + XCr0Flags::from_bits_truncate((high as u64) << 32 | (low as u64)) +} + +pub unsafe fn write_xcr0(value: XCr0Flags) { + let low = value.bits() as u32; + let high = (value.bits() >> 32) as u32; + + unsafe { + asm!( + "xsetbv", + in("ecx") 0, + in("rax") low, in("rdx") high, + options(nomem, nostack, preserves_flags), + ); + } +} + /// Write the given set of CR4 flags. /// /// ## Safety -/// - This function does not preserve the current value of the CR4 flags and -/// reserved fields. -/// - Its possible to violate memory safety by swapping CR4 flags. +/// * This function does not preserve the current value of the CR4 flags and reserved fields. +/// * Its possible to violate memory safety by swapping CR4 flags. pub unsafe fn write_cr4(value: Cr4Flags) { asm!("mov cr4, {}", in(reg) value.bits(), options(nostack, preserves_flags)); } @@ -243,9 +344,8 @@ pub unsafe fn write_cr4(value: Cr4Flags) { /// Write the given set of CR0 flags. /// /// ## Safety -/// - This function does not preserve the current value of the CR0 flags and -/// reserved fields. -/// - Its possible to violate memory safety by swapping CR0 flags. +/// * This function does not preserve the current value of the CR0 flags and reserved fields. +/// * Its possible to violate memory safety by swapping CR0 flags. pub unsafe fn write_cr0(value: Cr0Flags) { asm!("mov cr0, {}", in(reg) value.bits(), options(nostack, preserves_flags)); } @@ -273,3 +373,17 @@ pub fn read_cr2() -> VirtAddr { VirtAddr::new(value) } } + +pub fn read_mxcsr() -> MxCsr { + let mut mxcsr: u32 = 0; + unsafe { + asm!("stmxcsr [{}]", in(reg) &mut mxcsr, options(nostack, preserves_flags)); + } + MxCsr::from_bits_truncate(mxcsr) +} + +pub fn write_mxcsr(value: MxCsr) { + unsafe { + asm!("ldmxcsr [{}]", in(reg) &value, options(nostack, readonly)); + } +} diff --git a/src/aero_kernel/src/arch/x86_64/cpu_local.rs b/src/aero_kernel/src/arch/x86_64/cpu_local.rs new file mode 100644 index 00000000000..245921105a9 --- /dev/null +++ b/src/aero_kernel/src/arch/x86_64/cpu_local.rs @@ -0,0 +1,94 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::alloc::Layout; +use core::ops::{Deref, DerefMut}; + +use crate::extern_sym; +use crate::mem::paging::VirtAddr; + +use super::io; + +#[repr(C)] +pub struct CpuLocal(T); + +impl CpuLocal { + pub const fn new(val: T) -> Self { + Self(val) + } + + pub fn addr(&self) -> VirtAddr { + let val: u64; + + unsafe { + // gs:[0] -> SELF_PTR + asm!( + "mov {}, qword ptr gs:[0]", + lateout(reg) val, + options(nostack, preserves_flags, pure, readonly), + ); + } + + let self_addr = VirtAddr::new(self as *const _ as u64); + let section_addr = VirtAddr::new(extern_sym!(__cpu_local_start) as u64); + + let offset = self_addr - section_addr; + VirtAddr::new(val) + offset + } +} + +impl Deref for CpuLocal { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.addr().as_ptr() } + } +} + +impl DerefMut for CpuLocal { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.addr().as_mut_ptr() } + } +} + +/// The GS register holds a pointer to CPU-local data at a fixed offset of 0. While this approach +/// requires an additional memory lookup for accessing the data, it enables better code optimization +/// since the subsequent access is just a normal memory access. Considering the size of the +/// CPU-local data, this optimization is beneficial. +#[cpu_local(subsection = "self_ptr")] +static SELF_PTR: u64 = 0; + +#[cpu_local] +static mut CPUID: usize = 0; + +pub fn init(cpu_id: usize) { + let start = VirtAddr::new(extern_sym!(__cpu_local_start).addr() as u64); + let end = VirtAddr::new(extern_sym!(__cpu_local_end).addr() as u64); + + unsafe { + let size = end - start; + + let layout = Layout::from_size_align_unchecked(size as _, 64); + let data = alloc::alloc::alloc_zeroed(layout); + + core::ptr::copy_nonoverlapping::(start.as_ptr(), data, size as usize); + *data.cast::() = data as u64; + + io::wrmsr(io::IA32_GS_BASE, data as u64); + *CPUID = cpu_id; + } +} diff --git a/src/aero_kernel/src/arch/x86_64/gdt.rs b/src/aero_kernel/src/arch/x86_64/gdt.rs index 35e7723dc60..36c42f4c07c 100644 --- a/src/aero_kernel/src/arch/x86_64/gdt.rs +++ b/src/aero_kernel/src/arch/x86_64/gdt.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! The GDT contains entries telling the CPU about memory segments. //! @@ -27,39 +25,30 @@ //! * use core::alloc::Layout; -use core::mem; +use core::ptr::addr_of; +use core::{mem, ptr}; use alloc::alloc::alloc_zeroed; -use crate::arch::tls::PerCpuData; - -use super::{io, tls}; - -bitflags::bitflags! { - /// Specifies which element to load into a segment from - /// descriptor tables (i.e., is a index to LDT or GDT table - /// with some additional flags). - pub struct SegmentSelector: u16 { - const RPL_0 = 0b00; - const RPL_1 = 0b01; - const RPL_2 = 0b10; - const RPL_3 = 0b11; - const TI_GDT = 0 << 2; - const TI_LDT = 1 << 2; - } -} - bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] struct GdtEntryFlags: u8 { - const NULL = 0; const PROTECTED_MODE = 1 << 6; const LONG_MODE = 1 << 5; } } -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Ring { - Ring0 = 0b00, +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(u8)] +pub enum PrivilegeLevel { + Ring0 = 0, + Ring3 = 3, +} + +impl PrivilegeLevel { + pub fn is_user(&self) -> bool { + matches!(self, Self::Ring3) + } } const BOOT_GDT_ENTRY_COUNT: usize = 4; @@ -159,7 +148,7 @@ static GDT: [GdtEntry; GDT_ENTRY_COUNT] = [ // GDT TSS descriptor. GdtEntry::new( GdtAccessFlags::PRESENT | GdtAccessFlags::RING_3 | GdtAccessFlags::TSS_AVAIL, - GdtEntryFlags::NULL, + GdtEntryFlags::empty(), ), // GDT null descriptor as the TSS should be 16 bytes long // and twice the normal size. @@ -169,30 +158,55 @@ static GDT: [GdtEntry; GDT_ENTRY_COUNT] = [ struct GdtAccessFlags; impl GdtAccessFlags { + const EXECUTABLE: u8 = 1 << 3; const NULL: u8 = 0; const PRESENT: u8 = 1 << 7; + const PRIVILEGE: u8 = 1 << 1; const RING_0: u8 = 0 << 5; const RING_3: u8 = 3 << 5; const SYSTEM: u8 = 1 << 4; - const EXECUTABLE: u8 = 1 << 3; - const PRIVILEGE: u8 = 1 << 1; const TSS_AVAIL: u8 = 9; } -pub struct GdtEntryType; +pub struct GdtEntryIndex; -impl GdtEntryType { +#[rustfmt::skip] +impl GdtEntryIndex { pub const KERNEL_CODE: u16 = 1; pub const KERNEL_DATA: u16 = 2; pub const KERNEL_TLS: u16 = 3; + pub const USER_DATA: u16 = 4; + pub const USER_CODE: u16 = 5; pub const TSS: u16 = 8; pub const TSS_HI: u16 = 9; } +#[derive(Debug, Copy, Clone)] +#[repr(transparent)] +pub struct SegmentSelector(u16); + impl SegmentSelector { - const fn new(index: u16, rpl: Ring) -> Self { - Self { - bits: index << 3 | (rpl as u16), + pub const fn empty() -> Self { + Self(0) + } + + pub const fn new(index: u16, privilege_level: PrivilegeLevel) -> Self { + Self(index << 3 | (privilege_level as u16)) + } + + pub const fn bits(&self) -> u16 { + self.0 + } + + pub const fn from_bits(value: u16) -> Self { + Self(value) + } + + pub const fn privilege_level(&self) -> PrivilegeLevel { + match self.bits() & 0b11 { + 0 => PrivilegeLevel::Ring0, + 3 => PrivilegeLevel::Ring3, + _ => unreachable!(), } } } @@ -231,7 +245,7 @@ pub(super) struct GdtEntry { } impl GdtEntry { - const NULL: Self = Self::new(GdtAccessFlags::NULL, GdtEntryFlags::NULL); + const NULL: Self = Self::new(GdtAccessFlags::NULL, GdtEntryFlags::empty()); const fn new(access_flags: u8, entry_flags: GdtEntryFlags) -> Self { Self { @@ -257,7 +271,7 @@ impl GdtEntry { fn set_raw(&mut self, value: T) { unsafe { - *(self as *mut _ as *mut T) = value; + *(ptr::addr_of_mut!(*self).cast::()) = value; } } } @@ -272,7 +286,7 @@ pub struct Tss { /// The full 64-bit canonical forms of the stack pointers (RSP) for /// privilege levels 0-2. pub rsp: [u64; 3], // offset 0x04 - reserved2: u64, // offset 0x1C + pub reserved2: u64, // offset 0x1C /// The full 64-bit canonical forms of the interrupt stack table /// (IST) pointers. @@ -285,21 +299,26 @@ pub struct Tss { pub iomap_base: u16, // offset 0x66 } -// Processor Control Region -#[repr(C)] -pub struct Kpcr { - pub tss: Tss, - pub cpu_local: PerCpuData, -} +#[cpu_local(subsection = "tss")] +pub static mut TSS: Tss = Tss { + reserved: 0, + rsp: [0; 3], + reserved2: 0, + ist: [0; 7], + reserved3: 0, + reserved4: 0, + iomap_base: 0, +}; /// Initialize the bootstrap GDT which is required to initialize TLS (Thread Local Storage) /// support so, after the kernel heap we will map the TLS section and initialize the *actual* GDT -/// and then each CPU will have it's own GDT but we only will have to define it once as a `#[thread_local]`. +/// and then each CPU will have it's own GDT but we only will have to define it once as a +/// `#[thread_local]`. pub fn init_boot() { unsafe { let gdt_descriptor = GdtDescriptor::new( (mem::size_of::<[GdtEntry; BOOT_GDT_ENTRY_COUNT]>() - 1) as u16, - (&BOOT_GDT as *const _) as u64, + addr_of!(BOOT_GDT).addr() as u64, ); load_gdt(&gdt_descriptor); @@ -307,28 +326,49 @@ pub fn init_boot() { // Load the GDT segments. unsafe { - load_cs(SegmentSelector::new(GdtEntryType::KERNEL_CODE, Ring::Ring0)); - load_ds(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); - load_es(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); - load_fs(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); - load_gs(SegmentSelector::new(GdtEntryType::KERNEL_TLS, Ring::Ring0)); - load_ss(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); + load_cs(SegmentSelector::new( + GdtEntryIndex::KERNEL_CODE, + PrivilegeLevel::Ring0, + )); + + load_ds(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); + + load_es(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); + + load_fs(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); + + load_gs(SegmentSelector::new( + GdtEntryIndex::KERNEL_TLS, + PrivilegeLevel::Ring0, + )); + + load_ss(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); } } -pub fn get_task_state_segement() -> &'static mut Tss { - &mut get_kpcr().tss -} +static STK: [u8; 4096 * 16] = [0; 4096 * 16]; -pub fn get_kpcr() -> &'static mut Kpcr { - unsafe { &mut *(io::rdmsr(io::IA32_GS_BASE) as *mut Kpcr) } -} +pub const USER_SS: SegmentSelector = + SegmentSelector::new(GdtEntryIndex::USER_DATA, PrivilegeLevel::Ring3); -static STK: [u8; 4096 * 16] = [0; 4096 * 16]; +pub const USER_CS: SegmentSelector = + SegmentSelector::new(GdtEntryIndex::USER_CODE, PrivilegeLevel::Ring3); /// Initialize the *actual* GDT stored in TLS. /// -/// ## Saftey +/// ## Safety /// The heap must be initialized before this function is called. pub fn init() { let gdt = unsafe { @@ -338,7 +378,7 @@ pub fn init() { let gdt_size = gdt_ent_size * GDT_ENTRY_COUNT; let layout = Layout::from_size_align_unchecked(gdt_size, gdt_ent_align); - let ptr = alloc_zeroed(layout) as *mut GdtEntry; + let ptr = alloc_zeroed(layout).cast::(); core::slice::from_raw_parts_mut::(ptr, GDT_ENTRY_COUNT) }; @@ -346,14 +386,13 @@ pub fn init() { gdt.copy_from_slice(&GDT); unsafe { - let tss_ref = get_task_state_segement(); - let tss_ptr = tss_ref as *mut Tss; + let tss_ptr = TSS.addr().as_mut_ptr::(); - gdt[GdtEntryType::TSS as usize].set_offset(tss_ptr as u32); - gdt[GdtEntryType::TSS as usize].set_limit(mem::size_of::() as u32); - gdt[GdtEntryType::TSS_HI as usize].set_raw((tss_ptr as u64) >> 32); + gdt[GdtEntryIndex::TSS as usize].set_offset(tss_ptr as u32); + gdt[GdtEntryIndex::TSS as usize].set_limit(mem::size_of::() as u32); + gdt[GdtEntryIndex::TSS_HI as usize].set_raw((tss_ptr as u64) >> 32); - tss_ref.rsp[0] = STK.as_ptr().offset(4096 * 16) as u64; + TSS.rsp[0] = STK.as_ptr().offset(4096 * 16) as u64; let gdt_descriptor = GdtDescriptor::new( (mem::size_of::<[GdtEntry; GDT_ENTRY_COUNT]>() - 1) as u16, @@ -363,32 +402,45 @@ pub fn init() { load_gdt(&gdt_descriptor); // Reload the GDT segments. - load_cs(SegmentSelector::new(GdtEntryType::KERNEL_CODE, Ring::Ring0)); - load_ds(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); - load_es(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); - load_ss(SegmentSelector::new(GdtEntryType::KERNEL_DATA, Ring::Ring0)); + load_cs(SegmentSelector::new( + GdtEntryIndex::KERNEL_CODE, + PrivilegeLevel::Ring0, + )); + load_ds(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); + load_es(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); + load_ss(SegmentSelector::new( + GdtEntryIndex::KERNEL_DATA, + PrivilegeLevel::Ring0, + )); // Load the Task State Segment. - load_tss(SegmentSelector::new(GdtEntryType::TSS, Ring::Ring0)); + load_tss(SegmentSelector::new( + GdtEntryIndex::TSS, + PrivilegeLevel::Ring0, + )); } - // Now we update the per-cpu storage to store a reference - // to the per-cpu GDT. - tls::get_percpu().gdt = gdt; + // // Now we update the per-cpu storage to store a reference + // // to the per-cpu GDT. + // tls::get_percpu().gdt = gdt; } #[inline(always)] unsafe fn load_cs(selector: SegmentSelector) { - /* - * NOTE: We cannot directly move into CS since x86 requires the IP - * and CS set at the same time. To do this, we need push the new segment - * selector and return value onto the stack and far return to reload CS and - * continue execution. - * - * We also cannot use a far call or a far jump since we would only be - * able to jump to 32-bit instruction pointers. Only Intel supports for - * 64-bit far calls/jumps in long-mode, AMD does not. - */ + // NOTE: We cannot directly move into CS since x86 requires the IP + // and CS set at the same time. To do this, we need push the new segment + // selector and return value onto the stack and far return to reload CS and + // continue execution. + // + // We also cannot use a far call or a far jump since we would only be + // able to jump to 32-bit instruction pointers. Only Intel supports for + // 64-bit far calls/jumps in long-mode, AMD does not. asm!( "push {selector}", "lea {tmp}, [1f + rip]", diff --git a/src/aero_kernel/src/arch/x86_64/interrupts/exceptions.rs b/src/aero_kernel/src/arch/x86_64/interrupts/exceptions.rs index 38a38e5d8e3..aa27d868c7c 100644 --- a/src/aero_kernel/src/arch/x86_64/interrupts/exceptions.rs +++ b/src/aero_kernel/src/arch/x86_64/interrupts/exceptions.rs @@ -1,30 +1,31 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use super::{io, InterruptErrorStack}; use crate::arch::controlregs; -use crate::mem::paging::PageFaultErrorCode; +use crate::mem::paging::{PageFaultErrorCode, VirtAddr}; use crate::unwind; use crate::userland::scheduler; +#[cpu_local] +pub static mut PF_RESUME: VirtAddr = VirtAddr::new(0); + const LOG_PF_PTABLE: bool = true; macro interrupt_exception(fn $name:ident() => $message:expr) { @@ -32,7 +33,24 @@ macro interrupt_exception(fn $name:ident() => $message:expr) { unwind::prepare_panic(); log::error!("EXCEPTION: {}", $message); + log::error!("FS={:#x}", unsafe { io::rdmsr(io::IA32_FS_BASE) },); + log::error!("GS={:#x}", unsafe { io::rdmsr(io::IA32_GS_BASE) }); log::error!("Stack: {:#x?}", stack); + dbg!( + scheduler::get_scheduler() + .current_task() + .arch_task() + .fpu_storage + ); + + if stack.stack.iret.rip != 0 { + unsafe { + log::error!( + "RIP={:?}", + core::slice::from_raw_parts(stack.stack.iret.rip as *const u8, 512) + ); + } + } unwind::unwind_stack_trace(); @@ -49,7 +67,7 @@ interrupt_exception!(fn debug() => "Debug"); interrupt_exception!(fn non_maskable() => "Non Maskable"); interrupt_exception!(fn overflow() => "Stack Overflow"); interrupt_exception!(fn bound_range() => "Out of Bounds"); -interrupt_exception!(fn device_not_available() => "Device not Avaliable"); +interrupt_exception!(fn device_not_available() => "Device not Available"); interrupt_exception!(fn double_fault() => "Double Fault"); interrupt_exception!(fn invalid_tss() => "Invalid TSS"); interrupt_exception!(fn segment_not_present() => "Segment not Present"); @@ -58,10 +76,25 @@ interrupt_exception!(fn protection() => "Protection Fault"); interrupt_exception!(fn fpu_fault() => "FPU floating point fault"); interrupt_exception!(fn alignment_check() => "Alignment check fault"); interrupt_exception!(fn machine_check() => "Machine check fault"); -interrupt_exception!(fn simd() => "SIMD floating point fault"); interrupt_exception!(fn virtualization() => "Virtualization fault"); interrupt_exception!(fn security() => "Security exception"); +pub fn simd(stack: &mut InterruptErrorStack) { + unwind::prepare_panic(); + + log::error!("EXCEPTION: SIMD floating point fault"); + log::error!("Stack: {:#x?}", stack); + log::error!("MXCSR: {:?}", controlregs::read_mxcsr()); + + unwind::unwind_stack_trace(); + + unsafe { + loop { + super::halt(); + } + } +} + pub fn invalid_opcode(stack: &mut InterruptErrorStack) { // Catch SYSENTER on AMD CPUs. // @@ -103,10 +136,16 @@ pub fn breakpoint(stack: &mut InterruptErrorStack) { // // So we will set the RIP to RIP - 1, pointing to the int3 // instruction. - (*stack).stack.iret.rip -= 1; + stack.stack.iret.rip -= 1; } pub(super) fn page_fault(stack: &mut InterruptErrorStack) { + let pf_resume = unsafe { *PF_RESUME }; + if !pf_resume.is_zero() { + stack.stack.iret.rip = pf_resume.as_u64(); + return; + } + let accessed_address = controlregs::read_cr2(); let reason = PageFaultErrorCode::from_bits_truncate(stack.code); @@ -156,7 +195,6 @@ pub(super) fn page_fault(stack: &mut InterruptErrorStack) { .expect("userland application does not have a path set") ); - task.vm.log(); task.file_table.log(); if LOG_PF_PTABLE { @@ -167,6 +205,7 @@ pub(super) fn page_fault(stack: &mut InterruptErrorStack) { let task = scheduler::get_scheduler().current_task(); task.signal(aero_syscall::signal::SIGSEGV); + return; } else if !signal { } else { return; diff --git a/src/aero_kernel/src/arch/x86_64/interrupts/handlers.asm b/src/aero_kernel/src/arch/x86_64/interrupts/handlers.asm index 3e339fbaad0..2b1fa600ed7 100644 --- a/src/aero_kernel/src/arch/x86_64/interrupts/handlers.asm +++ b/src/aero_kernel/src/arch/x86_64/interrupts/handlers.asm @@ -39,6 +39,7 @@ interrupt_handler_%1: test qword [rsp + 16], 0x3 ; skip the SWAPGS instruction if CS & 0b11 == 0b00. jz .dont_swapgs + lfence swapgs .dont_swapgs: @@ -70,6 +71,7 @@ interrupt_handler_%1: test qword [rsp + 8], 0x3 ; skip the SWAPGS instruction if CS & 0b11 == 0b00. jz .dont_swapgs_again + lfence swapgs .dont_swapgs_again: diff --git a/src/aero_kernel/src/arch/x86_64/interrupts/idt.rs b/src/aero_kernel/src/arch/x86_64/interrupts/idt.rs index 6daee184279..57319b4a1d7 100644 --- a/src/aero_kernel/src/arch/x86_64/interrupts/idt.rs +++ b/src/aero_kernel/src/arch/x86_64/interrupts/idt.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! The IDT is similar to the Global Descriptor Table in structure. //! @@ -23,24 +21,15 @@ const IDT_ENTRIES: usize = 256; -pub(super) static mut IDT: [IdtEntry; IDT_ENTRIES] = [IdtEntry::NULL; IDT_ENTRIES]; +pub(super) static mut IDT: [IdtEntry; IDT_ENTRIES] = [IdtEntry::EMPTY; IDT_ENTRIES]; use core::mem::size_of; +use core::ptr::addr_of; -use crate::{arch::gdt::SegmentSelector, utils::sync::Mutex}; - -bitflags::bitflags! { - pub struct IDTFlags: u8 { - const PRESENT = 1 << 7; - const RING_0 = 0 << 5; - const RING_1 = 1 << 5; - const RING_2 = 2 << 5; - const RING_3 = 3 << 5; - const SS = 1 << 4; - const INTERRUPT = 0xE; - const TRAP = 0xF; - } -} +use bit_field::BitField; + +use crate::arch::gdt::{GdtEntryIndex, PrivilegeLevel, SegmentSelector}; +use crate::utils::sync::Mutex; #[repr(C, packed)] struct IdtDescriptor { @@ -56,47 +45,72 @@ impl IdtDescriptor { } } +#[derive(Debug, Copy, Clone)] +#[repr(C)] +struct EntryOptions { + cs: SegmentSelector, + bits: u16, +} + +impl EntryOptions { + #[inline] + const fn default() -> Self { + Self { + cs: SegmentSelector::empty(), + // bits 11:8 specify the gate-descriptor type, default to 64-bit interrupt gate (0xe). + bits: 0b1110_0000_0000, + } + } + + #[inline] + fn set_privilege_level(&mut self, dpl: PrivilegeLevel) { + self.bits.set_bits(13..15, dpl as u16); + } + + #[inline] + fn set_code_segment(&mut self, cs: SegmentSelector) { + self.cs = cs; + } + + #[inline] + fn set_present(&mut self, present: bool) { + self.bits.set_bit(15, present); + } +} + #[derive(Copy, Clone)] -#[repr(C, packed)] +#[repr(C)] pub(super) struct IdtEntry { - offset_low: u16, - selector: u16, - ist: u8, - type_attr: u8, - offset_middle: u16, - offset_hi: u32, + ptr_low: u16, + options: EntryOptions, + ptr_middle: u16, + ptr_high: u32, ignore: u32, } impl IdtEntry { - /// IDT entry with all values defaulted to 0, ie `null`. - const NULL: Self = Self { - offset_low: 0x00, - selector: 0x00, - ist: 0x00, - type_attr: 0x00, - offset_middle: 0x00, - offset_hi: 0x00, - ignore: 0x00, + const EMPTY: Self = Self { + ptr_low: 0, + options: EntryOptions::default(), + ptr_middle: 0, + ptr_high: 0, + ignore: 0, }; - /// Set the IDT entry flags. - fn set_flags(&mut self, flags: IDTFlags) { - self.type_attr = flags.bits; - } + pub(crate) fn set_function(&mut self, ptr: *const u8) { + self.options.set_privilege_level(PrivilegeLevel::Ring0); + self.options.set_code_segment(SegmentSelector::new( + GdtEntryIndex::KERNEL_CODE, + PrivilegeLevel::Ring0, + )); - /// Set the IDT entry offset. - fn set_offset(&mut self, selector: u16, base: usize) { - self.selector = selector; - self.offset_low = base as u16; - self.offset_middle = (base >> 16) as u16; - self.offset_hi = (base >> 32) as u32; - } + let addr = ptr.addr(); + + self.ptr_low = addr as u16; + self.ptr_middle = (addr >> 16) as u16; + self.ptr_high = (addr >> 32) as u32; - /// Set the handler function of the IDT entry. - pub(crate) fn set_function(&mut self, handler: *const u8) { - self.set_flags(IDTFlags::PRESENT | IDTFlags::RING_0 | IDTFlags::INTERRUPT); - self.set_offset(8, handler as usize); + self.options.set_present(true); } } @@ -137,7 +151,8 @@ pub struct IretRegisters { impl IretRegisters { pub fn is_user(&self) -> bool { - SegmentSelector::from_bits_truncate(self.cs as u16).contains(SegmentSelector::RPL_3) + let selector = SegmentSelector::from_bits(self.cs as u16); + selector.privilege_level().is_user() } } @@ -197,37 +212,35 @@ pub fn init() { INTERRUPT_HANDLERS.lock()[7] = IrqHandler::ErrorHandler(exceptions::device_not_available); INTERRUPT_HANDLERS.lock()[8] = IrqHandler::ErrorHandler(exceptions::double_fault); - // INTERRUPT_HANDLERS.lock()[9] is reserved. + // INTERRUPT_HANDLERS[9] is reserved. INTERRUPT_HANDLERS.lock()[10] = IrqHandler::ErrorHandler(exceptions::invalid_tss); INTERRUPT_HANDLERS.lock()[11] = IrqHandler::ErrorHandler(exceptions::segment_not_present); INTERRUPT_HANDLERS.lock()[12] = IrqHandler::ErrorHandler(exceptions::stack_segment); INTERRUPT_HANDLERS.lock()[13] = IrqHandler::ErrorHandler(exceptions::protection); INTERRUPT_HANDLERS.lock()[14] = IrqHandler::ErrorHandler(exceptions::page_fault); - // INTERRUPT_HANDLERS.lock()[15] is reserved. + // INTERRUPT_HANDLERS[15] is reserved. INTERRUPT_HANDLERS.lock()[16] = IrqHandler::ErrorHandler(exceptions::fpu_fault); INTERRUPT_HANDLERS.lock()[17] = IrqHandler::ErrorHandler(exceptions::alignment_check); INTERRUPT_HANDLERS.lock()[18] = IrqHandler::ErrorHandler(exceptions::machine_check); INTERRUPT_HANDLERS.lock()[19] = IrqHandler::ErrorHandler(exceptions::simd); INTERRUPT_HANDLERS.lock()[20] = IrqHandler::ErrorHandler(exceptions::virtualization); - // INTERRUPT_HANDLERS.lock()[21..29] are reserved. + // INTERRUPT_HANDLERS[21..29] are reserved. INTERRUPT_HANDLERS.lock()[30] = IrqHandler::ErrorHandler(exceptions::security); unsafe { let idt_descriptor = IdtDescriptor::new( ((IDT.len() * size_of::()) - 1) as u16, - (&IDT as *const _) as u64, + addr_of!(IDT).addr() as u64, ); load_idt(&idt_descriptor); - /* - * Since lazy statics are initialized on the their first dereference, we have to - * manually initialize the static as the first dereference happen in an IRQ interrupt. - * This means that the controller will never be initialized as an IRQ interrupt requires - * the controller to be initialized. - */ + // Since lazy statics are initialized on the their first dereference, we have to + // manually initialize the static as the first dereference happen in an IRQ interrupt. + // This means that the controller will never be initialized as an IRQ interrupt requires + // the controller to be initialized. lazy_static::initialize(&super::INTERRUPT_CONTROLLER); lazy_static::initialize(&super::PIC_CONTROLLER); lazy_static::initialize(&super::APIC_CONTROLLER); diff --git a/src/aero_kernel/src/arch/x86_64/interrupts/mod.rs b/src/aero_kernel/src/arch/x86_64/interrupts/mod.rs index 44d4cba9c05..fecaf75bbc3 100644 --- a/src/aero_kernel/src/arch/x86_64/interrupts/mod.rs +++ b/src/aero_kernel/src/arch/x86_64/interrupts/mod.rs @@ -1,23 +1,21 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -mod exceptions; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +pub mod exceptions; mod idt; use core::sync::atomic::{AtomicUsize, Ordering}; @@ -110,7 +108,7 @@ impl ApicController { /// PIC (Programmable Interrupt Controller) manages hardware interrupts and sends /// them to the appropriate system interrupt for the x86 architecture. Since APIC -/// has replaced PIC on modern systems, Aero disables PIC when APIC is avaliable. +/// has replaced PIC on modern systems, Aero disables PIC when APIC is available. /// /// ## Notes /// * @@ -261,7 +259,7 @@ pub fn allocate_vector() -> u8 { static IDT_FREE_VECTOR: Mutex = Mutex::new(32); let mut fvector = IDT_FREE_VECTOR.lock(); - let fcopy = fvector.clone(); + let fcopy = *fvector; if fcopy == 0xf0 { panic!("allocate_vector: vector allocation exhausted") diff --git a/src/aero_kernel/src/arch/x86_64/io.rs b/src/aero_kernel/src/arch/x86_64/io.rs index eb7060b6de1..f32d66dabe4 100644 --- a/src/aero_kernel/src/arch/x86_64/io.rs +++ b/src/aero_kernel/src/arch/x86_64/io.rs @@ -1,24 +1,24 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! Wrapper functions for the hardware IO using respective assembly instructions. +use crate::mem::paging::VirtAddr; + pub const IA32_EFER: u32 = 0xc0000080; /// Map of BASE Address of FS (R/W) See Table 35-2. @@ -228,3 +228,123 @@ impl BasedPort { unsafe { V::port_out(self.base + offset, value) } } } + +#[inline] +pub unsafe fn wrfsbase(base: VirtAddr) { + asm!("wrfsbase {}", in(reg) base.as_u64(), options(nostack, preserves_flags)); +} + +#[inline] +pub fn rdfsbase() -> VirtAddr { + unsafe { + let val: u64; + asm!("rdfsbase {}", out(reg) val, options(nomem, nostack, preserves_flags)); + + VirtAddr::new(val) + } +} + +#[inline] +pub unsafe fn wrgsbase(base: VirtAddr) { + asm!("wrgsbase {}", in(reg) base.as_u64(), options(nostack, preserves_flags)); +} + +#[inline] +pub fn rdgsbase() -> VirtAddr { + unsafe { + let val: u64; + asm!("rdgsbase {}", out(reg) val, options(nomem, nostack, preserves_flags)); + + VirtAddr::new(val) + } +} + +/// # Safety +/// The caller must ensure that the swap operation does not cause any undefined behavior. +#[inline(always)] +pub unsafe fn swapgs() { + asm!("swapgs", options(nostack, preserves_flags)); +} + +// XXX: There is no variant of the {rd,wr}gsbase instructions for accessing `KERNEL_GS_BASE`, so we +// wrap those in two `swapgs` instructions. This approach is still faster than reading/writing from +// the `KERNEL_GS_BASE` MSR. + +/// Sets the inactive `GS` segment's base address. +#[indirect] +pub fn set_inactive_gsbase() -> fn(base: VirtAddr) { + unsafe fn with_wrgsbase(base: VirtAddr) { + swapgs(); + wrgsbase(base); + swapgs(); + } + + unsafe fn with_wrmsr(base: VirtAddr) { + wrmsr(IA32_KERNEL_GSBASE, base.as_u64()); + } + + if super::has_fsgsbase() { + with_wrgsbase + } else { + with_wrmsr + } +} + +/// Returns the inactive `GS` segment's base address. +#[indirect] +pub fn get_inactive_gsbase() -> fn() -> VirtAddr { + fn with_rdgsbase() -> VirtAddr { + // SAFETY: The GS base is swapped back to the original value after the read. + unsafe { swapgs() }; + let base = rdgsbase(); + unsafe { swapgs() }; + + base + } + + fn with_rdmsr() -> VirtAddr { + VirtAddr::new(unsafe { rdmsr(IA32_KERNEL_GSBASE) }) + } + + if super::has_fsgsbase() { + with_rdgsbase + } else { + with_rdmsr + } +} + +/// Sets the `FS` segment's base address. +#[indirect] +pub fn set_fsbase() -> fn(base: VirtAddr) { + unsafe fn with_wrfsbase(base: VirtAddr) { + wrfsbase(base); + } + + unsafe fn with_wrmsr(base: VirtAddr) { + wrmsr(IA32_FS_BASE, base.as_u64()); + } + + if super::has_fsgsbase() { + with_wrfsbase + } else { + with_wrmsr + } +} + +/// Returns the `FS` segment's base address. +#[indirect] +pub fn get_fsbase() -> fn() -> VirtAddr { + fn with_rdfsbase() -> VirtAddr { + rdfsbase() + } + + fn with_rdmsr() -> VirtAddr { + VirtAddr::new(unsafe { rdmsr(IA32_FS_BASE) }) + } + + if super::has_fsgsbase() { + with_rdfsbase + } else { + with_rdmsr + } +} diff --git a/src/aero_kernel/src/arch/x86_64/mem.rs b/src/aero_kernel/src/arch/x86_64/mem.rs new file mode 100644 index 00000000000..5f439f1d5c3 --- /dev/null +++ b/src/aero_kernel/src/arch/x86_64/mem.rs @@ -0,0 +1,174 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::arch::naked_asm; + +fn should_store_by_byte() -> bool { + let cpuid = raw_cpuid::CpuId::new(); + if let Some(features) = cpuid.get_extended_feature_info() { + // Check if "Enhanced" or "Fast Short" optimizations are available. + features.has_rep_movsb_stosb() + } else { + false + } +} + +#[naked] +unsafe extern "C" fn memcpy_movsq(dest: *mut u8, src: *const u8, len: usize) -> *mut u8 { + // Registers used: + // + // %rdi = argument 1, `dest` + // %rsi = argument 2, `src` + // %rdx = argument 3, `len` + naked_asm!( + // Save the return value. + "mov rax, rdi", + // Copy in 8 byte chunks. + "mov rcx, rdx", + "shr rcx, 3", + "rep movsq", + // Copy the rest. + "mov rcx, rdx", + "and rcx, 0x7", + "rep movsb", + "ret", + ); +} + +#[naked] +unsafe extern "C" fn memcpy_movsb(dest: *mut u8, src: *const u8, len: usize) -> *mut u8 { + // Registers used: + // + // %rdi = argument 1, `dest` + // %rsi = argument 2, `src` + // %rdx = argument 3, `len` + naked_asm!( + // Save the return value. + "mov rax, rdi", + // Copy! + "mov rcx, rdx", + "rep movsb", + "ret", + ) +} + +#[indirect] +extern "C" fn memcpy() -> fn(dest: *mut u8, src: *const u8, len: usize) { + if should_store_by_byte() { + memcpy_movsb + } else { + memcpy_movsq + } +} + +#[naked] +unsafe extern "C" fn memset_stosq(dest: *mut u8, byte: i32, len: usize) -> *mut u8 { + // Registers used: + // + // %rdi = argument 1, `dest` + // %rsi = argument 2, `byte` + // %rdx = argument 3, `len` + naked_asm!( + // Save the return value. + "mov r11, rdi", + // Create an 8-byte copy of the pattern. + "mov rcx, rdx", + "movzx rax, sil", + "mov r10, 0x0101010101010101", + "mul r10", + "mov rdx, rcx", + // Copy in 8 byte chunks. + "shr rcx, 3", + "rep stosq", + // Copy the rest. + "mov rcx, rdx", + "and rcx, 0x7", + "rep stosb", + // Restore the return value. + "mov rax, r11", + "ret", + ) +} + +#[naked] +unsafe extern "C" fn memset_stosb(dest: *mut u8, byte: i32, len: usize) -> *mut u8 { + // Registers used: + // + // %rdi = argument 1, `dest` + // %rsi = argument 2, `byte` + // %rdx = argument 3, `len` + naked_asm!( + // Save the return value. + "mov r11, rdi", + "mov al, sil", + "mov rcx, rdx", + "rep stosb", + "mov rax, r11", + "ret", + ) +} + +#[indirect] +extern "C" fn memset() -> fn(dest: *mut u8, byte: i32, len: usize) { + if should_store_by_byte() { + memset_stosb + } else { + memset_stosq + } +} + +#[no_mangle] +#[naked] +unsafe extern "C" fn memmove_erms(dest: *mut u8, src: *const u8, len: usize) -> *mut u8 { + // Registers used: + // + // %rdi = argument 1, `dest` + // %rsi = argument 2, `src` + // %rdx = argument 3, `len` + naked_asm!( + "mov rax, rdi", + // Skip zero length. + "test rdx, rdx", + "jz 2f", + // Copying forwards: + "mov rcx, rdx", + "cmp rdi, rsi", + "jb 1f", + // `src` == `dest` + "je 2f", + "lea rdx, [rsi + rcx]", + "cmp rdi, rdx", + "jb 3f", + "1:", + "rep movsb", + "2:", + "ret", + // Copying backwards: + "3:", + "lea rdi, [rdi + rcx - 1]", + "lea rsi, [rsi + rcx - 1]", + "std", + "rep movsb", + "cld", + "ret", + ) +} + +#[no_mangle] +extern "C" fn memmove(dest: *mut u8, src: *const u8, len: usize) -> *mut u8 { + unsafe { memmove_erms(dest, src, len) } +} diff --git a/src/aero_kernel/src/arch/x86_64/mod.rs b/src/aero_kernel/src/arch/x86_64/mod.rs index 6fbf4cc7ccd..928404c15b3 100644 --- a/src/aero_kernel/src/arch/x86_64/mod.rs +++ b/src/aero_kernel/src/arch/x86_64/mod.rs @@ -1,116 +1,112 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +pub mod cpu_local; pub mod apic; pub mod controlregs; pub mod gdt; pub mod interrupts; pub mod io; +pub mod mem; pub mod signals; pub mod syscall; pub mod task; pub mod time; pub mod tls; +pub mod user_copy; +mod asm_macros; + +use core::cell::SyncUnsafeCell; use core::sync::atomic::Ordering; -use crate::acpi; use crate::acpi::aml; -use crate::cmdline; +use crate::{acpi, cmdline}; -use crate::mem; use crate::mem::paging; use crate::mem::paging::VirtAddr; -use crate::drivers; -use crate::logger; -use crate::rendy; +use crate::{drivers, logger, rendy}; use raw_cpuid::CpuId; -use limine::*; +use limine::request::*; +use limine::smp::Cpu; + +use spin::Once; use self::interrupts::INTERRUPT_CONTROLLER; -static MEMMAP: LimineMemmapRequest = LimineMemmapRequest::new(0); -static SMP: LimineSmpRequest = LimineSmpRequest::new(0); -static KERNEL_FILE: LimineKernelFileRequest = LimineKernelFileRequest::new(0); -static MODULES: LimineModuleRequest = LimineModuleRequest::new(0); -static FRAMEBUFFER: LimineFramebufferRequest = LimineFramebufferRequest::new(0); -static RSDP: LimineRsdpRequest = LimineRsdpRequest::new(0); -static BOOT_TIME: LimineBootTimeRequest = LimineBootTimeRequest::new(0); -static STACK: LimineStackSizeRequest = LimineStackSizeRequest::new(0).stack_size(0x1000 * 32); // 16KiB of stack for both the BSP and the APs -static HHDM: LimineHhdmRequest = LimineHhdmRequest::new(0); +static SMP: SyncUnsafeCell = SyncUnsafeCell::new(SmpRequest::new()); +static MEMMAP: SyncUnsafeCell = SyncUnsafeCell::new(MemoryMapRequest::new()); + +static KERNEL_FILE: KernelFileRequest = KernelFileRequest::new(); +static MODULES: ModuleRequest = ModuleRequest::new(); +static FRAMEBUFFER: FramebufferRequest = FramebufferRequest::new(); +static RSDP: RsdpRequest = RsdpRequest::new(); +static BOOT_TIME: BootTimeRequest = BootTimeRequest::new(); +static STACK: StackSizeRequest = StackSizeRequest::new().with_size(0x1000 * 32); // 16KiB of stack for both the BSP and the APs +static HHDM: HhdmRequest = HhdmRequest::new(); #[no_mangle] extern "C" fn arch_aero_main() -> ! { - unsafe { - core::ptr::read_volatile(STACK.get_response().as_ptr().unwrap()); - } - - // SAFETY: We have exclusive access to the memory map. - let memmap = MEMMAP - .get_response() - .get_mut() - .expect("limine: invalid memmap response") - .memmap_mut(); - - unsafe { - interrupts::disable_interrupts(); - } - - unsafe { - crate::PHYSICAL_MEMORY_OFFSET = VirtAddr::new(HHDM.get_response().get().unwrap().offset); - } - let kernel_file_resp = KERNEL_FILE .get_response() - .get() .expect("limine: invalid kernel file response"); - let kernel_file = kernel_file_resp - .kernel_file - .get() - .expect("limine: invalid kernel file pointer"); + let kernel_file = kernel_file_resp.file(); // Before we start the initialization process, we need to make sure - // the unwind info is avaliable; just in case if there is a kernel + // the unwind info is available; just in case if there is a kernel // panic, it will be able to unwind the stack. crate::unwind::UNWIND_INFO.call_once(|| { use crate::unwind::UnwindInfo; use xmas_elf::ElfFile; - let start = kernel_file - .base - .as_ptr() - .expect("limine: invalid kernel file base"); + let start = kernel_file.addr(); // SAFETY: The bootloader will provide a valid pointer to the kernel file. - let elf_slice = unsafe { core::slice::from_raw_parts(start, kernel_file.length as usize) }; + let elf_slice = unsafe { core::slice::from_raw_parts(start, kernel_file.size() as usize) }; let elf = ElfFile::new(elf_slice).expect("limine: invalid kernel file"); UnwindInfo::new(elf) }); + crate::relocate_self(); + + unsafe { + core::ptr::read_volatile(STACK.get_response().unwrap()); + } + + // SAFETY: We have exclusive access to the memory map. + let memmap = unsafe { &mut *MEMMAP.get() }.get_response_mut().unwrap(); + + unsafe { + interrupts::disable_interrupts(); + } + + unsafe { + crate::PHYSICAL_MEMORY_OFFSET = VirtAddr::new(HHDM.get_response().unwrap().offset()); + } + // Now that we have unwind info, we can initialize the COM ports. This // will be used to print panic messages/logs before the debug renderer is - // initialized to the serial output (if avaliable). + // initialized to the serial output (if available). drivers::uart::init(); logger::init(); @@ -119,42 +115,30 @@ extern "C" fn arch_aero_main() -> ! { let modules = MODULES .get_response() - .get() .expect("limine: invalid modules response") .modules(); - // Now, we need to parse the kernel command line so we can - // setup the debug renderer. - // - // SAFETY: The `cmdline` is a valid, aligned, and NULL terminated string. - let command_line = kernel_file - .cmdline - .to_str() - .expect("limine: bad command line"); - - let command_line = cmdline::parse( - command_line.to_str().expect("cmdline: invalid utf8"), - modules, - ); + let command_line = core::str::from_utf8(kernel_file.cmdline()).unwrap(); + let command_line = cmdline::parse(command_line, modules); paging::init(memmap).unwrap(); log::info!("loaded paging"); - mem::alloc::init_heap(); + crate::mem::alloc::init_heap(); log::info!("loaded heap"); // SMP initialization. - let smp_response = SMP.get_response().get_mut().unwrap(); - let bsp_lapic_id = smp_response.bsp_lapic_id; + let smp_response = unsafe { &mut *SMP.get() }.get_response_mut().unwrap(); + let bsp_lapic_id = smp_response.bsp_lapic_id(); - for cpu in smp_response.cpus().iter_mut() { + for cpu in smp_response.cpus_mut() { apic::CPU_COUNT.fetch_add(1, Ordering::SeqCst); if cpu.lapic_id == bsp_lapic_id { continue; } - cpu.goto_address = x86_64_aero_ap_main; + cpu.goto_address.write(x86_64_aero_ap_main); } gdt::init_boot(); @@ -164,14 +148,13 @@ extern "C" fn arch_aero_main() -> ! { let framebuffer = FRAMEBUFFER .get_response() - .get() .expect("limine: invalid framebuffer response") .framebuffers() - .first() + .next() .expect("limine: no framebuffer found!"); - rendy::init(&*framebuffer, &command_line); - logger::set_rendy_debug(command_line.rendy_debug); + rendy::init(framebuffer, &command_line); + logger::set_rendy_debug(true); interrupts::init(); log::info!("loaded IDT"); @@ -179,12 +162,13 @@ extern "C" fn arch_aero_main() -> ! { apic::init(); log::info!("loaded APIC"); - let rsdp = VirtAddr::new(RSDP.get_response().get().unwrap().address.as_ptr().unwrap() as u64); + let rsdp = VirtAddr::new(RSDP.get_response().unwrap().address().addr() as u64); acpi::init(rsdp); log::info!("loaded ACPI"); - tls::init(0); + tls::init(); + cpu_local::init(0); log::info!("loaded TLS"); crate::unwind::set_panic_hook_ready(true); @@ -194,32 +178,24 @@ extern "C" fn arch_aero_main() -> ! { syscall::init(); - crate::INITRD_MODULE.call_once(|| { - modules - .iter() - .find(|e| e.cmdline.to_str().unwrap().to_str().unwrap() == "initramfs") - .unwrap() - }); - - let boot_time = BOOT_TIME.get_response().get().unwrap(); - time::EPOCH.store(boot_time.boot_time as _, Ordering::SeqCst); + let boot_time = BOOT_TIME.get_response().unwrap(); + time::EPOCH.store(boot_time.boot_time().as_secs() as usize, Ordering::SeqCst); // Architecture init is done. Now we can initialize and start the init // process in the non-architecture specific part of the kernel. crate::aero_main(); } -#[no_mangle] -extern "C" fn x86_64_aero_ap_main(boot_info: *const LimineSmpInfo) -> ! { - let boot_info = unsafe { &*boot_info }; - let ap_id = boot_info.processor_id as usize; +extern "C" fn x86_64_aero_ap_main(cpu: &Cpu) -> ! { + let ap_id = cpu.id as usize; log::debug!("booting CPU {}", ap_id); gdt::init_boot(); log::info!("AP{}: loaded boot GDT", ap_id); - tls::init(ap_id); + tls::init(); + cpu_local::init(ap_id); log::info!("AP{}: loaded TLS", ap_id); gdt::init(); @@ -242,17 +218,40 @@ pub fn enable_acpi() { aml::get_subsystem().enable_acpi(INTERRUPT_CONTROLLER.method() as _); } +fn enable_xsave() { + use controlregs::XCr0Flags; + + // Enable XSAVE and x{get,set}bv + let mut cr4 = controlregs::read_cr4(); + cr4.insert(controlregs::Cr4Flags::OSXSAVE); + unsafe { controlregs::write_cr4(cr4) } + + let mut xcr0 = controlregs::read_xcr0(); + xcr0.insert(XCr0Flags::X87 | XCr0Flags::SSE | XCr0Flags::AVX); + // xcr0.insert(XCr0Flags::BNDREG | XCr0Flags::BNDCSR); + // xcr0.insert(XCr0Flags::ZMM_HI256 | XCr0Flags::HI16_ZMM | XCr0Flags::OPMASK); + unsafe { controlregs::write_xcr0(xcr0) } +} + +pub fn has_fsgsbase() -> bool { + static HAS_FSGSBASE: Once = Once::new(); + + *HAS_FSGSBASE.call_once(|| { + CpuId::new() + .get_extended_feature_info() + .unwrap() + .has_fsgsbase() + }) +} + pub fn init_cpu() { unsafe { // Enable the no-execute page protection feature. io::wrmsr(io::IA32_EFER, io::rdmsr(io::IA32_EFER) | 1 << 11); - // Check if SSE is supported. SSE support is a requirement for running Aero. - let has_sse = CpuId::new() - .get_feature_info() - .map_or(false, |i| i.has_sse()); + let features = CpuId::new().get_feature_info().unwrap(); - assert!(has_sse); + assert!(features.has_sse()); { let mut cr0 = controlregs::read_cr0(); @@ -269,7 +268,14 @@ pub fn init_cpu() { cr4.insert(controlregs::Cr4Flags::OSFXSR); cr4.insert(controlregs::Cr4Flags::OSXMMEXCPT_ENABLE); + if has_fsgsbase() { + cr4.insert(controlregs::Cr4Flags::FSGSBASE); + } + controlregs::write_cr4(cr4); } + + assert!(features.has_xsave(), "init: xsave not supported!"); + enable_xsave(); } } diff --git a/src/aero_kernel/src/arch/x86_64/signals.rs b/src/aero_kernel/src/arch/x86_64/signals.rs index 64682ce5098..4582aa1eaf3 100644 --- a/src/aero_kernel/src/arch/x86_64/signals.rs +++ b/src/aero_kernel/src/arch/x86_64/signals.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use aero_syscall::signal::{SigProcMask, SignalFlags}; use aero_syscall::SyscallError; @@ -52,20 +50,26 @@ impl SignalFrame { frame: &mut InterruptStack, sigmask: u64, ) -> SignalFrame { - SignalFrame { + let mut frame = SignalFrame { restart_syscall: if restart { frame.scratch.rax // syscall number } else { - syscall_result + u64::MAX }, frame: *frame, sigmask, + }; + + if !restart { + frame.frame.scratch.rax = syscall_result; } + + frame } } pub fn interrupt_check_signals(stack: &mut InterruptStack) { - // SAFTEY: If this interrupt did not originate from userland then we cannot + // SAFETY: If this interrupt did not originate from userland then we cannot // check for signals since the scheduler might not be initialized. if !stack.iret.is_user() { return; @@ -152,7 +156,7 @@ pub fn syscall_check_signals(syscall_result: isize, stack: &mut InterruptStack) } } -pub fn sigreturn(stack: &mut InterruptStack) -> usize { +pub fn sigreturn(stack: &mut InterruptStack) { let mut writer = StackHelper::new(&mut stack.iret.rsp); let signal_frame = unsafe { writer.get::() }; @@ -166,18 +170,9 @@ pub fn sigreturn(stack: &mut InterruptStack) -> usize { writer.get_by(REDZONE_SIZE); - let result = signal_frame.frame.scratch.rax; *stack = signal_frame.frame; if signal_frame.restart_syscall != u64::MAX { - #[cfg(feature = "syslog")] - log::debug!( - "sigreturn: restarting {} syscall", - aero_syscall::syscall_as_str(signal_frame.restart_syscall as _) - ); - stack.iret.rip -= SYSCALL_INSTRUCTION_SIZE; } - - result as usize } diff --git a/src/aero_kernel/src/arch/x86_64/syscall.rs b/src/aero_kernel/src/arch/x86_64/syscall.rs index 89846d616dd..2391a3b3e8b 100644 --- a/src/aero_kernel/src/arch/x86_64/syscall.rs +++ b/src/aero_kernel/src/arch/x86_64/syscall.rs @@ -1,24 +1,163 @@ use aero_syscall::SyscallError; use raw_cpuid::CpuId; -use crate::arch::gdt::GdtEntryType; +use crate::arch::gdt::{GdtEntryIndex, Tss, USER_CS, USER_SS}; use crate::mem::paging::VirtAddr; -use crate::userland::scheduler; +use crate::userland::scheduler::{self, ExitStatus}; use crate::utils::sync::IrqGuard; use super::interrupts::InterruptErrorStack; -use super::io; +use super::{asm_macros, io}; -extern "C" { - fn x86_64_syscall_handler(); - fn x86_64_sysenter_handler(); -} +use core::arch::naked_asm; +use core::mem::offset_of; const ARCH_SET_GS: usize = 0x1001; const ARCH_SET_FS: usize = 0x1002; const ARCH_GET_FS: usize = 0x1003; const ARCH_GET_GS: usize = 0x1004; +/// 64-bit SYSCALL instruction entry point. +/// +/// The instruction supports to to 6 arguments in registers. +/// +/// Registers state on entry: +/// * `RAX` - system call number +/// * `RCX` - return address +/// * `R11` - saved flags (note: R11 is callee-clobbered register in C ABI) +/// * `RDI` - argument 1 +/// * `RSI` - argument 2 +/// * `RDX` - argument 3 +/// * `R10` - argument 4 (needs to be moved to RCX to conform to C ABI) +/// * `R8` - argument 5 +/// * `R9` - argument 6 +/// +/// (note: `R12`..`R15`, `RBP`, `RBX` are callee-preserved in C ABI) +/// +/// The instruction saves the `RIP` to `RCX`, clears `RFLAGS.RF` then saves `RFLAGS` to `R11`. +/// Followed by, it loads the new `SS`, `CS`, and `RIP` from previously programmed MSRs. +/// +/// The instruction also does not save anything on the stack and does *not* change the `RSP`. +#[naked] +unsafe extern "C" fn x86_64_syscall_handler() { + naked_asm!( + // make the GS base point to the kernel TLS + "swapgs", + // save the user stack pointer + "mov qword ptr gs:{tss_temp_ustack_off}, rsp", + // restore kernel stack + "mov rsp, qword ptr gs:{tss_rsp0_off}", + "push {userland_ss}", + // push userspace stack ptr + "push qword ptr gs:{tss_temp_ustack_off}", + "push r11", + "push {userland_cs}", + "push rcx", + + "push rax", + asm_macros::push_scratch!(), + asm_macros::push_preserved!(), + + // push a fake error code to match with the layout of `InterruptErrorStack` + "push 0", + + "mov rdi, rsp", + + "cld", + "call {x86_64_do_syscall}", + "cli", + + // pop the fake error code + "add rsp, 8", + + asm_macros::pop_preserved!(), + asm_macros::pop_scratch!(), + + // cook the sysret frame + "pop rcx", + "add rsp, 8", + "pop r11", + "pop rsp", + + // restore user GS + "swapgs", + "sysretq", + + // constants: + userland_cs = const USER_CS.bits(), + userland_ss = const USER_SS.bits(), + // XXX: add 8 bytes to skip the x86_64 cpu local self ptr + tss_temp_ustack_off = const offset_of!(Tss, reserved2) + core::mem::size_of::(), + tss_rsp0_off = const offset_of!(Tss, rsp) + core::mem::size_of::(), + x86_64_do_syscall = sym x86_64_do_syscall, + ) +} + +/// 64-bit SYSENTER instruction entry point. +/// +/// The SYSENTER mechanism performs a fast transition to the kernel. +/// +/// The new `CS` is loaded from the `IA32_SYSENTER_CS` MSR, and the new instruction and stack +/// pointers are loaded from `IA32_SYSENTER_EIP` and `IA32_SYSENTER_ESP`, respectively. `RFLAGS.IF` +/// is cleared, but other flags are unchanged. +/// +/// As the instruction does not save *any* state, the user is required to provide the return `RIP` +/// and `RSP` in the `RCX` and `R11` registers, respectively. These addresses must be canonical. +/// +/// The instruction expects the call number and arguments in the same registers as for SYSCALL. +#[naked] +unsafe extern "C" fn x86_64_sysenter_handler() { + naked_asm!( + "swapgs", + // Build the interrupt frame expected by the kernel. + "push {userland_ss}", + "push r11", + "pushfq", + "push {userland_cs}", + "push rcx", + // Mask the same flags as for SYSCALL. + // XXX: Up to this point the code can be single-stepped if the user sets TF. + "pushfq", + "and dword ptr [rsp], 0x300", + "popfq", + "push rax", + asm_macros::push_scratch!(), + asm_macros::push_preserved!(), + "push 0", + // Store the stack pointer (interrupt frame ptr) in `RBP` for safe keeping, and align the + // stack as specified by the SysV calling convention. + "mov rbp, rsp", + "and rsp, ~0xf", + "mov rdi, rbp", + "call {x86_64_check_sysenter}", + "mov rdi, rbp", + "call {x86_64_do_syscall}", + // Reload the stack pointer, skipping the error code. + "lea rsp, [rbp + 8]", + asm_macros::pop_preserved!(), + asm_macros::pop_scratch!(), + // Pop the `IRET` frame into the registers expected by `SYSEXIT`. + "pop rdx", // return `RIP` in `RDX` + "add rsp, 8", + "popfq", // restore saved `RFLAGS` + "pop rcx", // return `RSP` in `RCX` + // SAFETY: The above call to `x86_64_check_sysenter` is guarantees that we execute + // `sysexit` with canonical addresses in RCX and RDX. Otherwise we would fault in the + // kernel having already swapped back to the user's GS. + "swapgs", + // SYSEXIT does *not* restore `IF` to re-enable interrupts. + // This is done here, rather then when restoring `RFLAGS` above, since `STI` will keep + "sti", + // interrupts inhibited until after the *following* instruction executes. + "sysexitq", + // constants: + userland_cs = const USER_CS.bits(), + userland_ss = const USER_SS.bits(), + x86_64_check_sysenter = sym x86_64_check_sysenter, + x86_64_do_syscall = sym x86_64_do_syscall, + ) +} + fn arch_prctl(command: usize, address: usize) -> Result { match command { ARCH_SET_FS => unsafe { @@ -63,7 +202,6 @@ fn arch_prctl(command: usize, address: usize) -> Result { /// /// We cannot execute `sysexit` on return with non-canonical return addresses, or we /// will take a fault in the kernel with the user's GS base already swapped back. -#[no_mangle] pub(super) extern "sysv64" fn x86_64_check_sysenter(stack: &mut InterruptErrorStack) { let rip = stack.stack.iret.rip; let rsp = stack.stack.iret.rsp; @@ -73,11 +211,10 @@ pub(super) extern "sysv64" fn x86_64_check_sysenter(stack: &mut InterruptErrorSt log::error!("bad sysenter: rip={:#018x},rsp={:#018x}", rip, rsp); // Forcibly kill the process, we have nowhere to return to. - scheduler::get_scheduler().exit(-1); + scheduler::get_scheduler().exit(ExitStatus::Normal(-1)); } } -#[no_mangle] pub(super) extern "C" fn x86_64_do_syscall(stack: &mut InterruptErrorStack) { let stack = &mut stack.stack; @@ -92,8 +229,7 @@ pub(super) extern "C" fn x86_64_do_syscall(stack: &mut InterruptErrorStack) { match syscall_number { // handle arch-specific syscalls (`sigreturn` and `arch_prctl`): aero_syscall::prelude::SYS_SIGRETURN => { - let result = super::signals::sigreturn(stack); - stack.scratch.rax = result as u64; + super::signals::sigreturn(stack); return; } @@ -128,12 +264,10 @@ pub(super) fn init() { assert!(has_syscall); unsafe { - /* - * Enable support for `syscall` and `sysret` instructions if the current - * CPU supports them and the target pointer width is 64. - */ - let syscall_base = GdtEntryType::KERNEL_CODE << 3; - let sysret_base = (GdtEntryType::KERNEL_TLS << 3) | 3; + // Enable support for `syscall` and `sysret` instructions if the current + // CPU supports them and the target pointer width is 64. + let syscall_base = GdtEntryIndex::KERNEL_CODE << 3; + let sysret_base = (GdtEntryIndex::KERNEL_TLS << 3) | 3; let star_hi = syscall_base as u32 | ((sysret_base as u32) << 16); @@ -148,23 +282,22 @@ pub(super) fn init() { io::wrmsr(io::IA32_EFER, efer | 1); } - /* - * Enable support for the `sysenter` instruction for system calls. - * - * This instruction is only supported on AMD processors in Legacy mode, - * not in Long mode (Compatibility or 64-bit modes), so still report support - * for it via `cpuid`. In this case the #UD exception is caught to handle the - * system call. - */ + // Enable support for the `sysenter` instruction for system calls. + // + // This instruction is only supported on AMD processors in Legacy mode, + // not in Long mode (Compatibility or 64-bit modes), so still report support + // for it via `cpuid`. In this case the #UD exception is caught to handle the + // system call. let has_sysenter = cpuid .get_feature_info() .map_or(false, |i| i.has_sysenter_sysexit()); if has_sysenter { + log::info!("enabling support for sysenter"); unsafe { io::wrmsr( io::IA32_SYSENTER_CS, - (GdtEntryType::KERNEL_CODE << 3) as u64, + (GdtEntryIndex::KERNEL_CODE << 3) as u64, ); io::wrmsr(io::IA32_SYSENTER_EIP, x86_64_sysenter_handler as u64); } diff --git a/src/aero_kernel/src/arch/x86_64/syscall_handler.asm b/src/aero_kernel/src/arch/x86_64/syscall_handler.asm deleted file mode 100644 index 8a1341fb307..00000000000 --- a/src/aero_kernel/src/arch/x86_64/syscall_handler.asm +++ /dev/null @@ -1,169 +0,0 @@ -; Copyright (C) 2021 The Aero Project Developers. -; -; This file is part of The Aero Project. -; -; Aero 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 of the License, or -; (at your option) any later version. -; -; Aero 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. -; -; You should have received a copy of the GNU General Public License -; along with Aero. If not, see . - -bits 64 - -%include "registers.inc" - -extern x86_64_do_syscall -extern x86_64_check_sysenter -global x86_64_syscall_handler - -%define TSS_TEMP_USTACK_OFF 0x1c -%define TSS_RSP0_OFF 0x04 - -%define USERLAND_SS 0x23 -%define USERLAND_CS 0x2b - -%define FMASK 0x300 ; TF | DF - -; 64-bit SYSCALL instruction entry point. The instruction supports -; to to 6 arguments in registers. -; -; Registers state on entry: -; RAX - system call number -; RCX - return address -; R11 - saved flags (note: R11 is callee-clobbered register in C ABI) -; RDI - argument 1 -; RSI - argument 2 -; RDX - argument 3 -; R10 - argument 4 (needs to be moved to RCX to conform to C ABI) -; R8 - argument 5 -; R9 - argument 6 -; -; (note: R12..R15, RBP, RBX are callee-preserved in C ABI) -; -; The instruction saves the RIP to RCX, cleares RFLAGS.RF then saves -; RFLAGS to R11. Followed by, it loads the new SS, CS, and RIP from -; previously programmed MSRs. -; -; The instruction also does not save anything on the stack and does -; *not* change the RSP. -x86_64_syscall_handler: - ; swap the GS base to ensure that it points to the - ; kernel PCR. - swapgs - - mov [gs:TSS_TEMP_USTACK_OFF], rsp ; save the user stack pointer - mov rsp, [gs:TSS_RSP0_OFF] ; restore the kernel stack pointer - push qword USERLAND_SS ; push userspace SS - push qword [gs:TSS_TEMP_USTACK_OFF] ; push userspace stack pointer - push r11 ; push RFLAGS - push qword USERLAND_CS ; push userspace CS - push rcx ; push userspace return pointer - - push rax - push_scratch - push_preserved - - ; push a "fake" error code to match with the layout of the - ; `InterruptErrorStack` structure. - push 0 - - mov rdi, rsp - - cld - call x86_64_do_syscall - cli - - ; pop the "fake" error code - add rsp, 8 - - pop_preserved - pop_scratch - - ; make the sysret frame - pop rcx - add rsp, 8 - pop r11 - - pop rsp - - swapgs - o64 sysret - -; 64-bit SYSENTER entry point -; -; The SYSENTER mechanism performs a fast transition to the kernel. -; The new CS is loaded from the IA32_SYSENTER_CS MSR, and the new instruction -; and stack pointers are loaded from IA32_SYSENTER_EIP and IA32_SYSENTER_ESP, -; respectively. RFLAGS.IF is cleared, but other flags are unchanged. -; -; As the instruction does not save *any* state, the user is required to provide -; the return RIP and RSP in the RCX and R11 registers, respectively. These -; addresses must be canonical. -; -; The instruction expects the call number and arguments in the same registers as -; for SYSCALL. -; -section .text.x86_64_sysenter_handler -global x86_64_sysenter_handler:function (x86_64_sysenter_handler.end - x86_64_sysenter_handler) -align 16 -x86_64_sysenter_handler: - swapgs - - ; Build the interrupt frame expected by the kernel. - push USERLAND_SS - push r11 - pushfq - push USERLAND_CS - push rcx - - ; Mask the same flags as for SYSCALL. - ; Note that up to this point the code can be single-stepped if the user sets TF. - pushfq - and dword [rsp], 0x300 - popfq - - push rax - push_scratch - push_preserved - push 0 - - ; Store the stack pointer (interrupt frame pointer) in RBP for safe keeping, - ; and align the stack as specified by the SysV calling convention. - mov rbp, rsp - and rsp, ~0xf - - mov rdi, rbp - call x86_64_check_sysenter - - mov rdi, rbp - call x86_64_do_syscall - - ; Reload the stack pointer, skipping the error code. - lea rsp, [rbp + 8] - pop_preserved - pop_scratch - - ; Pop the IRET frame into the registers expected by SYSEXIT. - pop rdx ; return RIP in RDX - add rsp, 8 - popfq ; restore saved RFLAGS - pop rcx ; return RSP in RCX - - ; SAFETY: The above call to `x86_64_check_sysenter` is guarantees that we - ; execute `sysexit` with canonical addresses in RCX and RDX. Otherwise we would - ; fault in the kernel having already swapped back to the user's GS. - swapgs - - ; SYSEXIT does *not* restore IF to re-enable interrupts. - ; This is done here, rather then when restoring RFLAGS above, since STI will - ; keep interrupts inhibited until after the *following* instruction executes. - sti - o64 sysexit -.end: diff --git a/src/aero_kernel/src/arch/x86_64/task.asm b/src/aero_kernel/src/arch/x86_64/task.asm deleted file mode 100644 index 029eb3d87d3..00000000000 --- a/src/aero_kernel/src/arch/x86_64/task.asm +++ /dev/null @@ -1,95 +0,0 @@ -; Copyright (C) 2021 The Aero Project Developers. -; -; This file is part of The Aero Project. -; -; Aero 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 of the License, or -; (at your option) any later version. -; -; Aero 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. -; -; You should have received a copy of the GNU General Public License -; along with Aero. If not, see . - -bits 64 - -%include "registers.inc" - -global jump_userland_exec -global task_spinup -global iretq_init -global fork_init - -jump_userland_exec: - push rdi ; Param: stack - push rsi ; Param: RIP - push rdx ; Param: RFLAGS - - cli - - pop r11 - pop rcx - pop rsp - - swapgs - o64 sysret - -iretq_init: - cli - - ; pop the error code - add rsp, 8 - - pop_preserved - pop_scratch - - iretq - -fork_init: - cli - - ; pop the error code - add rsp, 8 - - pop_preserved - pop_scratch - - swapgs - iretq - -; extern "C" fn task_spinup(prev: &mut Context, next: &mut Context) -; -; Saves the current context into `prev` and restore the context from `next`. -task_spinup: - ; save callee-saved registers and this must match - ; the ordering of the fields in the `Context` struct. - push rbp - push rbx - push r12 - push r13 - push r14 - push r15 - - mov rax, cr3 ; save CR3 - push rax - - mov [rdi], rsp ; update old context pointer with current stack pointer - mov rsp, rsi ; switch to new stack - - pop rax ; restore CR3 - mov cr3, rax - - ; restore callee-saved registers - pop r15 - pop r14 - pop r13 - pop r12 - pop rbx - pop rbp - - ; resume the next thread - ret diff --git a/src/aero_kernel/src/arch/x86_64/task.rs b/src/aero_kernel/src/arch/x86_64/task.rs index 36b682064d1..fa57318ba88 100644 --- a/src/aero_kernel/src/arch/x86_64/task.rs +++ b/src/aero_kernel/src/arch/x86_64/task.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! ## How does `x86_64` context switching work? //! @@ -36,8 +34,10 @@ use alloc::alloc::alloc_zeroed; use aero_syscall::{MMapFlags, MMapProt}; use alloc::vec::Vec; +use raw_cpuid::CpuId; use core::alloc::Layout; +use core::arch::naked_asm; use core::ptr::Unique; use crate::arch::interrupts::InterruptErrorStack; @@ -47,7 +47,7 @@ use crate::syscall::ExecArgs; use crate::userland::vm::Vm; use crate::utils::StackHelper; -use super::{controlregs, io}; +use super::{asm_macros, controlregs, io}; use crate::mem::AddressSpace; @@ -70,48 +70,123 @@ struct Context { #[repr(u64)] #[derive(Debug, Copy, Clone)] pub enum AuxvType { - AtNull = 0, - AtPhdr = 3, - AtPhEnt = 4, - AtPhNum = 5, - AtEntry = 9, + Null = 0, + Phdr = 3, + PhEnt = 4, + PhNum = 5, + Entry = 9, + Secure = 23, } /// Returns the first address outside the user range. /// /// ## Notes -/// * On Intel CPUs, if a SYSCALL instruction is at the highest canonical address, then -/// that syscall will enter the kernel with a non-canonical return address, and SYSRET will -/// explode dangerously. We avoid this particular problem by preventing anything from -/// being mapped at the maximum canonical address. +/// * On Intel CPUs, if a SYSCALL instruction is at the highest canonical address, then that syscall +/// will enter the kernel with a non-canonical return address, and SYSRET will explode +/// dangerously. We avoid this particular problem by preventing anything from being mapped at the +/// maximum canonical address. /// /// * On AMD CPUs in the Ryzen family, there's a nasty bug in which the CPUs malfunction if they -/// execute code from the highest canonical page. They'll speculate right off the end of the canonical -/// space and bad things happen. This is worked around in the same way as the Intel problem. +/// execute code from the highest canonical page. They'll speculate right off the end of the +/// canonical space and bad things happen. This is worked around in the same way as the Intel +/// problem. pub fn userland_last_address() -> VirtAddr { // Reference: https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/page_64.h#L61 static CACHED: spin::Once = spin::Once::new(); *CACHED.call_once(|| { - let virtual_mask_shift: u64; let la57 = crate::mem::paging::level_5_paging_enabled(); - - if la57 { - virtual_mask_shift = 56; - } else { - virtual_mask_shift = 47; - } + let virtual_mask_shift: u64 = if la57 { 56 } else { 47 }; VirtAddr::new((1u64 << virtual_mask_shift) - Size4KiB::SIZE) }) } +/// Returns whether the given pointer is within the userland address space. +pub fn user_access_ok(ptr: *const T) -> bool { + let size = core::mem::size_of::(); + VirtAddr::new(ptr as u64 + size as u64) <= super::task::userland_last_address() +} + const USERLAND_STACK_SIZE: u64 = 0x64000; //(1 << 47) - (Size4KiB::SIZE * 2) const USERLAND_STACK_TOP: VirtAddr = VirtAddr::new(0x7fffffffe000); const USERLAND_STACK_BOTTOM: VirtAddr = USERLAND_STACK_TOP.const_sub_u64(USERLAND_STACK_SIZE); +#[naked] +unsafe extern "C" fn jump_userland_exec(stack: VirtAddr, rip: VirtAddr, rflags: u64) { + #[rustfmt::skip] + naked_asm!( + "push rdi", // stack + "push rsi", // rip + "push rdx", // rflags + "cli", + "pop r11", + "pop rcx", + "pop rsp", + "swapgs", + "sysretq" + ); +} + +#[naked] +unsafe extern "C" fn task_spinup(prev: &mut Unique, next: &Context) { + naked_asm!( + // save callee-saved registers + "push rbp", + "push rbx", + "push r12", + "push r13", + "push r14", + "push r15", + // save CR3 + "mov rax, cr3", + "push rax", + // update old context + "mov [rdi], rsp", + // switch to new stack + "mov rsp, rsi", + // restore CR3 + "pop rax", + "mov cr3, rax", + // restore callee-saved registers + "pop r15", + "pop r14", + "pop r13", + "pop r12", + "pop rbx", + "pop rbp", + // resume the next thread + "ret", + ); +} + +#[naked] +unsafe extern "C" fn iretq_init() { + naked_asm!( + "cli", + // pop the error code + "add rsp, 8", + asm_macros::pop_preserved!(), + asm_macros::pop_scratch!(), + "iretq", + ) +} + +#[naked] +unsafe extern "C" fn fork_init() { + naked_asm!( + "cli", + // pop the error code + "add rsp, 8", + asm_macros::pop_preserved!(), + asm_macros::pop_scratch!(), + "swapgs", + "iretq", + ) +} + pub struct ArchTask { context: Unique, @@ -121,6 +196,8 @@ pub struct ArchTask { fs_base: VirtAddr, gs_base: VirtAddr, + + pub fpu_storage: Option, } impl ArchTask { @@ -130,12 +207,14 @@ impl ArchTask { context_switch_rsp: VirtAddr::zero(), // Since the IDLE task is a special kernel task, we use the kernel's - // address space here and we also use the kernel privilage level here. + // address space here and we also use the kernel privilege level here. address_space: AddressSpace::this(), user: false, fs_base: VirtAddr::zero(), gs_base: VirtAddr::zero(), + + fpu_storage: None, } } @@ -160,10 +239,6 @@ impl ArchTask { kframe.stack.iret.rsp = task_stack as u64; kframe.stack.iret.rflags = if enable_interrupts { 0x200 } else { 0x00 }; - extern "C" { - fn iretq_init(); - } - let context = unsafe { stack.offset::() }; *context = Context::default(); @@ -178,6 +253,8 @@ impl ArchTask { fs_base: VirtAddr::zero(), gs_base: VirtAddr::zero(), + + fpu_storage: None, } } @@ -202,25 +279,24 @@ impl ArchTask { let old_registers_frame = unsafe { old_stack.offset::() }; let registers_frame = unsafe { new_stack.offset::() }; - *registers_frame = InterruptErrorStack::default(); + *registers_frame = *old_registers_frame; - registers_frame.stack.iret.cs = old_registers_frame.stack.iret.cs; - registers_frame.stack.iret.ss = old_registers_frame.stack.iret.ss; + // registers_frame.stack.iret.cs = old_registers_frame.stack.iret.cs; + // registers_frame.stack.iret.ss = old_registers_frame.stack.iret.ss; + // registers_frame.stack.iret.rflags = old_registers_frame.stack.iret.rflags; registers_frame.stack.iret.rip = entry as _; registers_frame.stack.iret.rsp = usr_stack as _; - registers_frame.stack.iret.rflags = 0x200; + // registers_frame.stack.iret.rflags = 0x200; let context = unsafe { new_stack.offset::() }; - extern "C" { - fn fork_init(); - } - *context = Context::default(); context.rip = fork_init as _; context.cr3 = address_space.cr3().start_address().as_u64(); + let mut fpu_storage = self.fpu_storage.unwrap().clone(); + Ok(Self { context: unsafe { Unique::new_unchecked(context) }, context_switch_rsp: VirtAddr::new(switch_stack as u64), @@ -228,16 +304,16 @@ impl ArchTask { user: true, // The FS and GS bases are inherited from the parent process. - fs_base: self.fs_base.clone(), - gs_base: self.gs_base.clone(), + fs_base: VirtAddr::new(1), + gs_base: self.gs_base, + + fpu_storage: Some(fpu_storage), }) } - pub fn fork(&self) -> Result> { + pub fn fork(&self, address_space: AddressSpace) -> Result> { assert!(self.user, "cannot fork a kernel task"); - let new_address_space = AddressSpace::this().offset_page_table().fork()?; - // Since the fork function marks all of the userspace entries in both the forked // and the parent address spaces as read only, we will flush the page table of the // current process to trigger COW. @@ -264,30 +340,30 @@ impl ArchTask { // Prepare the trampoline... let context = unsafe { new_stack.offset::() }; - extern "C" { - fn fork_init(); - } - *context = Context::default(); context.rip = fork_init as u64; - context.cr3 = new_address_space.cr3().start_address().as_u64(); + context.cr3 = address_space.cr3().start_address().as_u64(); + + let fpu_storage = self.fpu_storage.unwrap().clone(); Ok(Self { context: unsafe { Unique::new_unchecked(context) }, context_switch_rsp: VirtAddr::new(switch_stack as u64), - address_space: new_address_space, + address_space, user: true, // The FS and GS bases are inherited from the parent process. - fs_base: self.fs_base.clone(), - gs_base: self.gs_base.clone(), + fs_base: self.fs_base, + gs_base: self.gs_base, + + fpu_storage: Some(fpu_storage), }) } pub fn exec( &mut self, vm: &Vm, - executable: DirCacheItem, + executable: &DirCacheItem, argv: Option, envv: Option, @@ -316,8 +392,6 @@ impl ArchTask { None, ); - vm.log(); - address_space.switch(); // Perform the address space switch self.context = Unique::dangling(); @@ -326,9 +400,32 @@ impl ArchTask { self.fs_base = VirtAddr::zero(); self.gs_base = VirtAddr::zero(); - extern "C" { - fn jump_userland_exec(stack: VirtAddr, rip: VirtAddr, rflags: u64); - } + let mut fpu_storage = FpuState::default(); + + // unsafe { + // xrstor(&fpu_storage); + + // // The x87 FPU control word is set to 0x37f (default), which masks all + // // floating-point exceptions, sets rounding to nearest, and sets the x87 + // // FPU precision to 64 bits (as documented in Intel SDM volume 1 section + // // 8.1.5). + // const DEFAULT_FPU_CWORD: u16 = 0x37f; + // asm!("fldcw [{}]", in(reg) &DEFAULT_FPU_CWORD, options(nomem)); + + // // Set the default MXCSR value at reset as documented in Intel SDM volume 2A. + // controlregs::write_mxcsr( + // MxCsr::INVALID_OPERATION_MASK + // | MxCsr::DENORMAL_MASK + // | MxCsr::DIVIDE_BY_ZERO_MASK + // | MxCsr::OVERFLOW_MASK + // | MxCsr::UNDERFLOW_MASK + // | MxCsr::PRECISION_MASK, + // ); + + // xsave(&mut fpu_storage); + // } + + self.fpu_storage = Some(fpu_storage); let mut stack_addr = USERLAND_STACK_TOP.as_u64(); let mut stack = StackHelper::new(&mut stack_addr); @@ -336,13 +433,13 @@ impl ArchTask { let mut envp = Vec::new(); let mut argp = Vec::new(); - loaded_binary - .envv - .map(|envv| envp = envv.push_into_stack(&mut stack)); + if let Some(envv) = loaded_binary.envv { + envp = envv.push_into_stack(&mut stack); + } - loaded_binary - .argv - .map(|argv| argp = argv.push_into_stack(&mut stack)); + if let Some(argv) = loaded_binary.argv { + argp = argv.push_into_stack(&mut stack); + } stack.align_down(); @@ -357,18 +454,19 @@ impl ArchTask { let p2_header = loaded_binary.elf.header.pt2; unsafe { - let hdr: [(AuxvType, usize); 4] = [ + let hdr: [(AuxvType, usize); 5] = [ ( - AuxvType::AtPhdr, + AuxvType::Phdr, (p2_header.ph_offset() + loaded_binary.base_addr.as_u64()) as usize, ), - (AuxvType::AtPhEnt, p2_header.ph_entry_size() as usize), - (AuxvType::AtPhNum, p2_header.ph_count() as usize), - (AuxvType::AtEntry, p2_header.entry_point() as usize), + (AuxvType::PhEnt, p2_header.ph_entry_size() as usize), + (AuxvType::PhNum, p2_header.ph_count() as usize), + (AuxvType::Entry, p2_header.entry_point() as usize), + (AuxvType::Secure, 0), ]; stack.write(0usize); // Make it 16 bytes aligned - stack.write(AuxvType::AtNull); + stack.write(AuxvType::Null); stack.write(hdr); } @@ -400,11 +498,9 @@ impl ArchTask { /// Allocates a new context switch stack for the process and returns the stack /// top address. See the module level documentation for more information. fn alloc_switch_stack() -> Result> { - let frame: PhysFrame = FRAME_ALLOCATOR - .allocate_frame() - .ok_or(MapToError::FrameAllocationFailed)?; + let frame = FRAME_ALLOCATOR.alloc_zeroed(4096 * 4).unwrap(); - Ok(frame.start_address().as_hhdm_virt() + Size4KiB::SIZE) + Ok(frame.as_hhdm_virt() + (4096u64 * 4)) } fn unref_pt(&mut self) { @@ -454,8 +550,8 @@ impl ArchTask { /// belongs to. This is required since we also update the GS base register with the /// `base` immediately (not waiting for a switch). pub unsafe fn set_gs_base(&mut self, base: VirtAddr) { - io::wrmsr(io::IA32_KERNEL_GSBASE, base.as_u64()); self.gs_base = base; + io::set_inactive_gsbase(base); } /// Returns the saved FS base for this task. @@ -470,28 +566,128 @@ impl ArchTask { /// belongs to. This is required since we also update the FS base register with the /// `base` immediately (not waiting for a switch). pub unsafe fn set_fs_base(&mut self, base: VirtAddr) { - io::wrmsr(io::IA32_FS_BASE, base.as_u64()); self.fs_base = base; + io::set_fsbase(base); } } -/// Check out the module level documentation for more information. -pub fn arch_task_spinup(from: &mut ArchTask, to: &ArchTask) { - extern "C" { - fn task_spinup(from: &mut Unique, to: &Context); +fn xsave_size() -> u32 { + static XSAVE_SIZE: spin::Once = spin::Once::new(); + *XSAVE_SIZE.call_once(|| { + CpuId::new() + .get_extended_state_info() + .expect("xsave: cpuid extended state info unavailable") + .xsave_size() + }) +} + +#[derive(Debug, Copy, Clone)] +#[repr(C, align(16))] +pub struct FpuState { + /// x87 FPU Control Word (16 bits). See Figure 8-6 in the Intel® 64 and IA-32 Architectures + /// Software Developer’s Manual Volume 1, for the layout of the x87 FPU control word. + pub fcw: u16, + /// x87 FPU Status Word (16 bits). + pub fsw: u16, + /// x87 FPU Tag Word (8 bits) + reserved (8 bits). + pub ftw: u16, + /// x87 FPU Opcode (16 bits). + pub fop: u16, + /// x87 FPU Instruction Pointer Offset ([31:0]). The contents of this field differ depending on + /// the current addressing mode (32-bit, 16-bit, or 64-bit) of the processor when the + /// FXSAVE instruction was executed: 32-bit mode — 32-bit IP offset. 16-bit mode — low 16 + /// bits are IP offset; high 16 bits are reserved. 64-bit mode with REX.W — 64-bit IP + /// offset. 64-bit mode without REX.W — 32-bit IP offset. + pub fip: u32, + /// x87 FPU Instruction Pointer Selector (16 bits) + reserved (16 bits). + pub fcs: u32, + /// x87 FPU Instruction Operand (Data) Pointer Offset ([31:0]). The contents of this field + /// differ depending on the current addressing mode (32-bit, 16-bit, or 64-bit) of the + /// processor when the FXSAVE instruction was executed: 32-bit mode — 32-bit DP offset. + /// 16-bit mode — low 16 bits are DP offset; high 16 bits are reserved. 64-bit mode + /// with REX.W — 64-bit DP offset. 64-bit mode without REX.W — 32-bit DP offset. + pub fdp: u32, + /// x87 FPU Instruction Operand (Data) Pointer Selector (16 bits) + reserved. + pub fds: u32, + /// MXCSR Register State (32 bits). + pub mxcsr: u32, + /// This mask can be used to adjust values written to the MXCSR register, ensuring that + /// reserved bits are set to 0. Set the mask bits and flags in MXCSR to the mode of + /// operation desired for SSE and SSE2 SIMD floating-point instructions. + pub mxcsr_mask: u32, + /// x87 FPU or MMX technology registers. Layout: [12 .. 9 | 9 ... 0] LHS = reserved; RHS = mm. + pub mm: [u128; 8], + /// XMM registers (128 bits per field). + pub xmm: [u128; 16], + /// reserved. + pub _pad: [u64; 12], +} + +impl Default for FpuState { + fn default() -> Self { + Self { + mxcsr: 0x1f80, + mxcsr_mask: 0x037f, + // rest are zeroed + fcw: 0, + fsw: 0, + ftw: 0, + fop: 0, + fip: 0, + fcs: 0, + fdp: 0, + fds: 0, + mm: [0; 8], + xmm: [u128::MAX; 16], + _pad: [0; 12], + } } +} + +fn xsave(fpu: &mut FpuState) { + // The implicit EDX:EAX register pair specifies a 64-bit instruction mask. The specific state + // components saved correspond to the bits set in the requested-feature bitmap (RFBM), which is + // the logical-AND of EDX:EAX and XCR0. + // unsafe { + // asm!("xsave64 [{}]", in(reg) fpu.as_ptr(), in("eax") u32::MAX, in("edx") u32::MAX, + // options(nomem, nostack)) } + + use core::arch::x86_64::_fxsave64; + + unsafe { _fxsave64((fpu as *mut FpuState).cast()) } +} + +fn xrstor(fpu: &FpuState) { + // unsafe { + // asm!("xrstor [{}]", in(reg) fpu.as_ptr(), in("eax") u32::MAX, in("edx") u32::MAX, + // options(nomem, nostack)); } + use core::arch::x86_64::_fxrstor64; + + unsafe { _fxrstor64((fpu as *const FpuState).cast()) } +} +/// Check out the module level documentation for more information. +pub fn arch_task_spinup(from: &mut ArchTask, to: &ArchTask) { unsafe { + if let Some(fpu) = from.fpu_storage.as_mut() { + xsave(fpu); + } + + if let Some(fpu) = to.fpu_storage.as_ref() { + xrstor(fpu); + } + // Load the new thread's kernel stack pointer everywhere it's needed. let kstackp = to.context_switch_rsp.as_u64(); - super::gdt::get_task_state_segement().rsp[0] = kstackp; + super::gdt::TSS.rsp[0] = kstackp; io::wrmsr(io::IA32_SYSENTER_ESP, kstackp); - // switch to the new FS base. - io::wrmsr(io::IA32_FS_BASE, to.fs_base.as_u64()); + // Preserve and restore the %fs, %gs bases. + from.fs_base = io::get_fsbase(); + from.gs_base = io::get_inactive_gsbase(); - // update the swap GS target to point to the new GS base. - io::wrmsr(io::IA32_KERNEL_GSBASE, to.gs_base.as_u64()); + io::set_fsbase(to.fs_base); + io::set_inactive_gsbase(to.gs_base); task_spinup(&mut from.context, to.context.as_ref()); } diff --git a/src/aero_kernel/src/arch/x86_64/time.rs b/src/aero_kernel/src/arch/x86_64/time.rs index 7fabaf15b5d..4c5e5e82baf 100644 --- a/src/aero_kernel/src/arch/x86_64/time.rs +++ b/src/aero_kernel/src/arch/x86_64/time.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! The PIT (Programmable Interval Timer) chip basically consists of an oscillator, //! a prescaler and 3 independent frequency dividers and it is used to create time intervals @@ -111,6 +109,7 @@ fn pit_irq_handler(_stack: &mut InterruptStack) { if value % PIT_FREQUENCY_HZ == 0 { UPTIME_SEC.fetch_add(1, Ordering::Relaxed); // Increment uptime seconds + crate::syscall::time::check_timers(); } } diff --git a/src/aero_kernel/src/arch/x86_64/tls.rs b/src/aero_kernel/src/arch/x86_64/tls.rs index 1bb776c6d13..d9bf49d81cf 100644 --- a/src/aero_kernel/src/arch/x86_64/tls.rs +++ b/src/aero_kernel/src/arch/x86_64/tls.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! Thread Local Storage (TLS) are per-thread global variables. On 64-bit each CPU core's //! `fs` GDT segment points to the thread local memory area where the thread local static's @@ -25,14 +23,8 @@ //! * //! * -use core::alloc::Layout; - -use alloc::alloc::alloc_zeroed; use alloc::vec::Vec; -use super::gdt::*; -use super::io; - use crate::utils::sync::Mutex; use raw_cpuid::FeatureInfo; @@ -111,36 +103,11 @@ pub struct CpuInfo { pub features: Vec<&'static &'static str>, } -#[repr(C)] -pub struct PerCpuData { - pub cpuid: usize, - pub lapic_timer_frequency: u32, - - pub(super) gdt: &'static mut [GdtEntry], -} - -/// SAFETY: The GS base should point to the kernel PCR. pub fn get_cpuid() -> usize { - get_percpu().cpuid + 0 } -/// SAFETY: The GS base should point to the kernel PCR. -pub fn get_percpu() -> &'static mut PerCpuData { - &mut get_kpcr().cpu_local -} - -pub fn init(cpuid: usize) { - // NOTE: Inside kernel space, the GS base will always point to the CPU local data and when - // jumping to userland `swapgs` is called making the GS base point to the userland TLS data. - unsafe { - let kpcr_layout = Layout::new::(); - - let kpcr_ptr = alloc_zeroed(kpcr_layout) as *mut Kpcr; - io::wrmsr(io::IA32_GS_BASE, kpcr_ptr as u64); - } - - get_percpu().cpuid = cpuid; - +pub fn init() { let cpuid = raw_cpuid::CpuId::new(); let features = cpuid @@ -152,7 +119,7 @@ pub fn init(cpuid: usize) { .map(|(name, _)| name) .collect::>() }) - .unwrap_or(Vec::new()); + .unwrap_or_default(); CPU_INFO.lock().push(CpuInfo { cpuid: 0, @@ -177,6 +144,6 @@ where let lock = CPU_INFO.lock(); for info in lock.iter() { - f(&info); + f(info); } } diff --git a/src/aero_kernel/src/arch/x86_64/user_copy.rs b/src/aero_kernel/src/arch/x86_64/user_copy.rs new file mode 100644 index 00000000000..5922b3fb2ce --- /dev/null +++ b/src/aero_kernel/src/arch/x86_64/user_copy.rs @@ -0,0 +1,182 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::arch::naked_asm; +use core::fmt::{Debug, Display}; +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; + +use crate::interrupts::exceptions::PF_RESUME; +use crate::mem::paging::VirtAddr; +use crate::syscall::SysArg; + +use super::task::user_access_ok; + +/// Copy to/from a block of data from user space. Returns whether the copy was successful. +/// +/// # Safety +/// The caller must ensure that: +/// * If copying to userspace, the `dest` pointer must be within the userland address space. +/// * If copying from userspace, the `dest` pointer must be valid for `size` bytes. +/// +/// ## Concurrent Accesses +/// Concurrent access, *including potential data races with userspace memory*, are permitted since +/// other userspace threads or processes may modify the memory concurrently. This behavior is +/// similar to how [`std::io`] permits data races with file contents on disk. +/// +/// [`std::io`]: https://doc.rust-lang.org/std/io/index.html +#[naked] +unsafe extern "C" fn copy_to_from_user( + dest: *mut u8, + src: *const u8, + size: usize, + + fault_resume: *const u8, +) -> bool { + // Registers used: + // + // %rdi = argument 1, `dest` + // %rsi = argument 2, `src` + // %rdx = argument 3, `size` + // %rcx = argument 4, `fault_resume` (copied to %r10) + naked_asm!( + // Copy `fault_resume` out of %rcx because it will be utilized by `rep movsb` latter. + "mov r10, rcx", + // Setup the page fault resume. + "lea rax, 1f", + "mov [r10], rax", + // XXX: From this point until the fault return is reset, no function calls or stack + // manipulations should be performed. We must ensure the ability to restore all callee + // registers without any knowledge of the exact location within this code where a fault may + // occur. + // + // Copy 8 bytes at a time and then one byte at a time for the remainder. + "mov rcx, rdx", + "shr rcx, 3", + "rep movsq", + "and edx, 7", + "je 2f", + "mov ecx, edx", + "rep movsb", + // Set return value to `true`. + "2:", + "mov eax, 1", + // Reset the `fault_resume` pointer and return. + "3:", + "mov qword ptr [r10], 0", + "ret", + // `fault_resume` handler - set return value to `false` and return. + "1:", + "xor eax, eax", + "jmp 3b", + ) +} + +/// Copy a structure from userspace memory. Returns whether the copy was successful. +#[must_use] +fn copy_from_user(dest: &mut MaybeUninit, src: *const T) -> bool { + let fault_resume = unsafe { PF_RESUME.addr() }.as_ptr(); + let size = core::mem::size_of::(); + + user_access_ok(src); + + // SAFETY: We have verified that the `src` pointer is within the userland address space. + unsafe { copy_to_from_user(dest.as_mut_ptr().cast(), src.cast(), size, fault_resume) } +} + +/// Copy a structure from userspace memory. Returns whether the copy was successful. +#[must_use] +fn copy_to_user(dest: *mut T, src: &T) -> bool { + let fault_resume = unsafe { PF_RESUME.addr() }.as_ptr(); + let size = core::mem::size_of::(); + let src_ptr = src as *const T; + + user_access_ok(dest); + + // SAFETY: We have verified that the `dest` pointer is within the userland address space. + unsafe { copy_to_from_user(dest.cast(), src_ptr.cast(), size, fault_resume) } +} + +/// A reference to a structure in userspace memory, which can be either read-only or read-write. +/// +/// Concurrent access, *including data races to/from userspace memory*, are permitted. See the +/// documentation of [`copy_to_from_user`] for more information. +pub struct UserRef { + ptr: *mut T, + val: T, +} + +impl UserRef { + pub unsafe fn new(address: VirtAddr) -> Self { + let mut val = MaybeUninit::::uninit(); + + // FIXME: Return an error if the copy fails. + assert!(copy_from_user(&mut val, address.as_ptr())); + + Self { + ptr: address.as_mut_ptr(), + // SAFETY: We have initialized the value via `copy_from_user` above. + val: unsafe { val.assume_init() }, + } + } + + pub fn take(self) -> T + where + T: Clone, + { + self.val.clone() + } +} + +impl Deref for UserRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.val + } +} + +impl DerefMut for UserRef { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.val + } +} + +impl Drop for UserRef { + fn drop(&mut self) { + assert!(copy_to_user(self.ptr, &self.val)); + } +} + +impl Display for UserRef { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.val.fmt(f) + } +} + +impl Debug for UserRef { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "UserRef({:?})", self.val) + } +} + +impl SysArg for UserRef { + fn from_usize(value: usize) -> Self { + // TODO: SAFETY + unsafe { Self::new(VirtAddr::new(value.try_into().unwrap())) } + } +} diff --git a/src/aero_kernel/src/cmdline.rs b/src/aero_kernel/src/cmdline.rs index 682c9c949d4..0cd47c1fe8e 100644 --- a/src/aero_kernel/src/cmdline.rs +++ b/src/aero_kernel/src/cmdline.rs @@ -1,8 +1,26 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + use core::num::ParseIntError; -use limine::{LimineFile, NonNullPtr}; use spin::Once; +use limine::file::File; + use crate::rendy; static RAW_CMDLINE_STR: Once<&'static str> = Once::new(); @@ -27,16 +45,14 @@ impl CommandLine { } } -fn resolve_module(modules: &[NonNullPtr], name: &str) -> &'static [u8] { +fn resolve_module(modules: &[&File], name: &str) -> &'static [u8] { modules .iter() .find(|m| { - let n = m.cmdline.to_str().unwrap().to_str().unwrap(); + let n = core::str::from_utf8(m.cmdline()).unwrap(); n == name }) - .map(|m| unsafe { - core::slice::from_raw_parts(m.base.as_ptr().unwrap(), m.length as usize) - }) + .map(|m| unsafe { core::slice::from_raw_parts(m.addr(), m.size() as usize) }) .expect("resolve_module: invalid operand") } @@ -51,11 +67,11 @@ fn parse_number(mut string: &str) -> Result { string = string.trim_start_matches("0o"); usize::from_str_radix(string, 8) } else { - usize::from_str_radix(string, 10) + string.parse::() } } -pub fn parse(cmdline: &'static str, modules: &[NonNullPtr]) -> CommandLine { +pub fn parse(cmdline: &'static str, modules: &[&File]) -> CommandLine { RAW_CMDLINE_STR.call_once(|| cmdline); // Chew up the leading spaces. @@ -110,8 +126,7 @@ pub fn parse(cmdline: &'static str, modules: &[NonNullPtr]) -> Comma /// Returns the raw kernel command line string. /// /// ## Panics -/// * If this function was invoked before the kernel command line was -/// parsed using [`self::parse`]. +/// * If this function was invoked before the kernel command line was parsed using [`self::parse`]. pub fn get_raw_cmdline() -> &'static str { RAW_CMDLINE_STR .get() diff --git a/src/aero_kernel/src/drivers/block/ahci.rs b/src/aero_kernel/src/drivers/block/ahci.rs index 124346dce83..02b05f04345 100644 --- a/src/aero_kernel/src/drivers/block/ahci.rs +++ b/src/aero_kernel/src/drivers/block/ahci.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::sync::Arc; @@ -23,10 +21,11 @@ use alloc::vec::Vec; use bit_field::BitField; use spin::Once; -use crate::mem::{paging::*, AddressSpace}; +use crate::mem::paging::*; +use crate::mem::AddressSpace; use crate::utils::sync::Mutex; -use crate::utils::{CeilDiv, VolatileCell}; +use crate::utils::VolatileCell; use crate::drivers::pci::*; @@ -92,6 +91,7 @@ bitflags::bitflags! { } bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] struct HbaHostCont: u32 { const HR = 1 << 0; // HBA Reset const IE = 1 << 1; // Interrupt Enable @@ -101,6 +101,7 @@ bitflags::bitflags! { } bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] struct HbaPortIS: u32 { const DHRS = 1 << 0; // Device to Host Register FIS Interrupt const PSS = 1 << 1; // PIO Setup FIS Interrupt @@ -123,6 +124,7 @@ bitflags::bitflags! { } bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] struct HbaPortIE: u32 { const DHRE = 1 << 0; // Device to Host Register FIS Interrupt const PSE = 1 << 1; // PIO Setup FIS Interrupt @@ -145,6 +147,7 @@ bitflags::bitflags! { } bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] struct HbaPortCmd: u32 { const ST = 1 << 0; // Start const SUD = 1 << 1; // Spin-Up Device @@ -169,8 +172,12 @@ bitflags::bitflags! { } } +#[derive(Debug, Copy, Clone)] +#[repr(transparent)] +struct HbaCmdHeaderFlags(u16); + bitflags::bitflags! { - struct HbaCmdHeaderFlags: u16 { + impl HbaCmdHeaderFlags: u16 { const A = 1 << 5; // ATAPI const W = 1 << 6; // Write const P = 1 << 7; // Prefetchable @@ -181,11 +188,11 @@ bitflags::bitflags! { } impl HbaCmdHeaderFlags { - /// Sets the length of the command FIS. The HBA uses this field to know the - /// length of the FIS it shall send to the device. + /// Sets the length of the command FIS. The HBA uses this field to know the length of the FIS it + /// shall send to the device. #[inline] fn set_command_fis_size(&mut self, size: usize) { - self.bits.set_bits(0..=4, size as _); + self.0.set_bits(0..=4, size as _); } } @@ -202,7 +209,7 @@ pub struct DmaBuffer { impl DmaBuffer { pub fn sectors(&self) -> usize { - self.data_size.ceil_div(512) + self.data_size.div_ceil(512) } pub fn start(&self) -> PhysAddr { @@ -253,13 +260,13 @@ impl DmaRequest { self.sector } - /// Copys the data from the DMA buffer into the given buffer. + /// Copies the data from the DMA buffer into the given buffer. pub fn copy_into(&self, into: &mut [u8]) { let mut offset = 0x00; // Keep track of the offset - let mut remaning = into.len(); // Keep track of the remaining data + let mut remaining = into.len(); // Keep track of the remaining data for buffer in self.buffer.iter() { - let count = core::cmp::min(remaning, 0x2000); + let count = core::cmp::min(remaining, 0x2000); let buffer_pointer = buffer.start.as_hhdm_virt().as_ptr(); let buffer = unsafe { core::slice::from_raw_parts::(buffer_pointer, count) }; @@ -268,7 +275,7 @@ impl DmaRequest { // calculated offset. into[offset..offset + count].copy_from_slice(buffer); - remaning -= count; // Subtract the size from the remaining size. + remaining -= count; // Subtract the size from the remaining size. offset += count; // Add the size to the offset. } } @@ -279,9 +286,9 @@ impl DmaRequest { match self.command { DmaCommand::Read => { if lba48 { - AtaCommand::AtaCommandReadDmaExt + AtaCommand::ReadDmaExt } else { - AtaCommand::AtaCommandReadDma + AtaCommand::ReadDma } } } @@ -296,65 +303,59 @@ impl DmaRequest { #[derive(Debug, PartialEq, Copy, Clone)] #[repr(u8)] pub enum AtaCommand { - AtaCommandWriteDma = 0xCA, - AtaCommandWriteDmaQueued = 0xCC, - AtaCommandWriteMultiple = 0xC5, - AtaCommandWriteSectors = 0x30, + WriteDma = 0xCA, + WriteDmaQueued = 0xCC, + WriteMultiple = 0xC5, + WriteSectors = 0x30, - AtaCommandReadDma = 0xC8, - AtaCommandReadDmaQueued = 0xC7, - AtaCommandReadMultiple = 0xC4, - AtaCommandReadSectors = 0x20, + ReadDma = 0xC8, + ReadDmaQueued = 0xC7, + ReadMultiple = 0xC4, + ReadSectors = 0x20, - AtaCommandWriteDmaExt = 0x35, - AtaCommandWriteDmaQueuedExt = 0x36, - AtaCommandWriteMultipleExt = 0x39, - AtaCommandWriteSectorsExt = 0x34, + WriteDmaExt = 0x35, + WriteDmaQueuedExt = 0x36, + WriteMultipleExt = 0x39, + WriteSectorsExt = 0x34, - AtaCommandReadDmaExt = 0x25, - AtaCommandReadDmaQueuedExt = 0x26, - AtaCommandReadMultipleExt = 0x29, - AtaCommandReadSectorsExt = 0x24, + ReadDmaExt = 0x25, + ReadDmaQueuedExt = 0x26, + ReadMultipleExt = 0x29, + ReadSectorsExt = 0x24, - AtaCommandPacket = 0xA0, - AtaCommandDeviceReset = 0x08, + Packet = 0xA0, + DeviceReset = 0x08, - AtaCommandService = 0xA2, - AtaCommandNop = 0, - AtaCommandNopNopAutopoll = 1, + Service = 0xA2, + Nop = 0, + NopNopAutopoll = 1, - AtaCommandGetMediaStatus = 0xDA, + GetMediaStatus = 0xDA, - AtaCommandFlushCache = 0xE7, - AtaCommandFlushCacheExt = 0xEA, + FlushCache = 0xE7, + FlushCacheExt = 0xEA, - AtaCommandDataSetManagement = 0x06, + DataSetManagement = 0x06, - AtaCommandMediaEject = 0xED, + MediaEject = 0xED, - AtaCommandIdentifyPacketDevice = 0xA1, - AtaCommandIdentifyDevice = 0xEC, + IdentifyPacketDevice = 0xA1, + IdentifyDevice = 0xEC, - AtaCommandSetFeatures = 0xEF, - AtaCommandSetFeaturesEnableReleaseInt = 0x5D, - AtaCommandSetFeaturesEnableServiceInt = 0x5E, - AtaCommandSetFeaturesDisableReleaseInt = 0xDD, - AtaCommandSetFeaturesDisableServiceInt = 0xDE, + SetFeatures = 0xEF, + SetFeaturesEnableReleaseInt = 0x5D, + SetFeaturesEnableServiceInt = 0x5E, + SetFeaturesDisableReleaseInt = 0xDD, + SetFeaturesDisableServiceInt = 0xDE, } impl AtaCommand { pub fn is_lba48(&self) -> bool { - match self { - AtaCommand::AtaCommandReadDmaExt | AtaCommand::AtaCommandWriteDmaExt => true, - _ => false, - } + matches!(self, AtaCommand::ReadDmaExt | AtaCommand::WriteDmaExt) } pub fn is_write(&self) -> bool { - match self { - AtaCommand::AtaCommandWriteDmaExt | AtaCommand::AtaCommandWriteDma => true, - _ => false, - } + matches!(self, AtaCommand::WriteDmaExt | AtaCommand::WriteDma) } } @@ -434,7 +435,7 @@ impl HbaCmdTbl { } fn prdt_entry_mut(&mut self, i: usize) -> &mut HbaPrdtEntry { - unsafe { &mut *self.prdt_entry.as_mut_ptr().offset(i as isize) } + unsafe { &mut *self.prdt_entry.as_mut_ptr().add(i) } } } @@ -564,10 +565,8 @@ impl HbaPort { fn start(&mut self, offset_table: &mut OffsetPageTable) -> Result<(), MapToError> { self.stop_cmd(); // Stop the command engine before starting the port - /* - * size = sizeof(CTB) * 32 == 4KiB * 2 (so we need to allocate - * two 4KiB size frames). - */ + // size = sizeof(CTB) * 32 == 4KiB * 2 (so we need to allocate + // two 4KiB size frames). let frame_addr = pmm_alloc(BuddyOrdering::Size8KiB); let page_addr = crate::IO_VIRTUAL_BASE + frame_addr.as_u64(); @@ -634,7 +633,7 @@ impl HbaPort { let ipm = status.interface_power_management(); let dd = status.device_detection(); - // Check if the port is active and is present. If thats the case + // Check if the port is active and is present. If that's the case // we can start the AHCI port. if let (HbaPortDd::PresentAndE, HbaPortIpm::Active) = (dd, ipm) { log::trace!("ahci: enabling port {}", port); @@ -658,8 +657,7 @@ impl HbaPort { let header = self.cmd_header_at(slot); let mut flags = header.flags.get(); - if command == AtaCommand::AtaCommandWriteDmaExt || command == AtaCommand::AtaCommandWriteDma - { + if command == AtaCommand::WriteDmaExt || command == AtaCommand::WriteDma { flags.insert(HbaCmdHeaderFlags::W); // If its a write command add the write flag. } else { flags.remove(HbaCmdHeaderFlags::W); // If its a read command remove the write flag. @@ -728,7 +726,7 @@ impl HbaPort { impl HbaMemory { fn port_mut(&mut self, port: usize) -> &mut HbaPort { - unsafe { &mut *((self as *mut Self).offset(1) as *mut HbaPort).offset(port as isize) } + unsafe { &mut *((self as *mut Self).offset(1) as *mut HbaPort).add(port) } } } @@ -872,16 +870,12 @@ impl AhciProtected { if port.probe(offset_table, i)? { // Get the address of the HBA port. let address = VirtAddr::new(port as *const _ as _); - - drop(port); // Drop the reference to the port. - drop(hba); // Drop the reference to the HBA. - let port = Arc::new(AhciPort::new(address)); // Add the port to the ports array. self.ports[i] = Some(port); - // Workaround to get access to the HBA and still satify the + // Workaround to get access to the HBA and still satisfy the // borrow checker. hba = self.hba_mem(); } @@ -939,11 +933,10 @@ struct AhciDriver { impl PciDeviceHandle for AhciDriver { fn handles(&self, vendor_id: Vendor, device_id: DeviceType) -> bool { - match (vendor_id, device_id) { - (Vendor::Intel, DeviceType::SataController) => true, - - _ => false, - } + matches!( + (vendor_id, device_id), + (Vendor::Intel, DeviceType::SataController) + ) } fn start(&self, header: &PciHeader, _offset_table: &mut OffsetPageTable) { @@ -985,4 +978,4 @@ pub fn ahci_init() { register_device_driver(get_ahci().clone()); } -crate::module_init!(ahci_init); +crate::module_init!(ahci_init, ModuleType::Block); diff --git a/src/aero_kernel/src/drivers/block/ide/channel.rs b/src/aero_kernel/src/drivers/block/ide/channel.rs index 07bef7fc810..420a2c45a8a 100644 --- a/src/aero_kernel/src/drivers/block/ide/channel.rs +++ b/src/aero_kernel/src/drivers/block/ide/channel.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::sync::Arc; use bit_field::BitField; @@ -123,12 +121,12 @@ impl IdeChannelData { self.base.set_drive_select(slave, false, 0); delay(1000); - self.base.set_command(AtaCommand::AtaCommandIdentifyDevice); + self.base.set_command(AtaCommand::IdentifyDevice); delay(1000); let status = self.base.status(); - if status == BaseStatusReg::empty() { + if status.is_empty() { return false; } @@ -148,15 +146,7 @@ impl IdeChannelData { let lm = self.base.lba_mid(); let lh = self.base.lba_hi(); - match (lm, lh) { - (0x0, 0x0) => { - return true; - } - - _ => {} - } - - return false; + lm == 0 && lh == 0 } pub fn setup_prdt(&mut self) { diff --git a/src/aero_kernel/src/drivers/block/ide/mod.rs b/src/aero_kernel/src/drivers/block/ide/mod.rs index 830f4e76398..f15d05ded6a 100644 --- a/src/aero_kernel/src/drivers/block/ide/mod.rs +++ b/src/aero_kernel/src/drivers/block/ide/mod.rs @@ -1,25 +1,25 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . mod channel; mod registers; +use core::mem::MaybeUninit; + use channel::*; use alloc::sync::Arc; @@ -32,7 +32,6 @@ use crate::fs::block::{BlockDevice, BlockDeviceInterface}; use crate::mem::paging::OffsetPageTable; use crate::utils::sync::Mutex; -use crate::utils::CeilDiv; use super::ahci::DmaRequest; @@ -50,20 +49,43 @@ impl IdeDrive { } impl BlockDeviceInterface for IdeDrive { - fn read(&self, sector: usize, dest: &mut [u8]) -> Option { - let count = dest.len().ceil_div(512); + fn read_block(&self, sector: usize, dest: &mut [MaybeUninit]) -> Option { + let count = dest.len().div_ceil(512); let request = Arc::new(DmaRequest::new(sector, count)); - let res = self.channel.run_request(request.clone(), self.slave); + let res = self.channel.run_request(request, self.slave); if res.is_some() { - request.copy_into(dest); + todo!() + // request.copy_into(dest); } res } - fn write(&self, _sector: usize, _buf: &[u8]) -> Option { + fn block_size(&self) -> usize { + todo!() + } + + fn read_dma( + &self, + _sector: usize, + _start: crate::mem::paging::PhysAddr, + _size: usize, + ) -> Option { + unimplemented!() + } + + fn write_dma( + &self, + _sector: usize, + _start: crate::mem::paging::PhysAddr, + _size: usize, + ) -> Option { + todo!() + } + + fn write_block(&self, _sector: usize, _buf: &[u8]) -> Option { unimplemented!() } } @@ -154,22 +176,11 @@ impl IdeDevice { if idx > 0 { header.enable_bus_mastering(); - for channel in self - .channels - .iter_mut() - .filter(|a| a.is_some()) - .map(|a| a.as_mut().unwrap()) - { + for channel in self.channels.iter_mut().filter_map(|a| a.as_mut()) { channel.init(); } - for (i, drive) in self - .ide_devs - .iter() - .filter(|e| e.is_some()) - .map(|e| e.as_ref().unwrap()) - .enumerate() - { + for (i, drive) in self.ide_devs.iter().filter_map(|e| e.as_ref()).enumerate() { let name = alloc::format!("blck{}", i); let block_device = BlockDevice::new(name, drive.clone()); @@ -185,11 +196,10 @@ struct Ide { impl PciDeviceHandle for Ide { fn handles(&self, vendor_id: Vendor, device_id: DeviceType) -> bool { - match (vendor_id, device_id) { - (Vendor::Intel, DeviceType::IdeController) => true, - - _ => false, - } + matches!( + (vendor_id, device_id), + (Vendor::Intel, DeviceType::IdeController) + ) } fn start(&self, header: &PciHeader, _offset_table: &mut OffsetPageTable) { @@ -213,4 +223,4 @@ fn init() { register_device_driver(get_device().clone()); } -crate::module_init!(init); +crate::module_init!(init, ModuleType::Block); diff --git a/src/aero_kernel/src/drivers/block/ide/registers.rs b/src/aero_kernel/src/drivers/block/ide/registers.rs index 66e7f2d208b..3b22a83124d 100644 --- a/src/aero_kernel/src/drivers/block/ide/registers.rs +++ b/src/aero_kernel/src/drivers/block/ide/registers.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use bit_field::BitField; @@ -79,7 +77,7 @@ impl BaseDriveSelReg { bitflags::bitflags! { pub struct BaseStatusReg: u8 { - const ERR = 0b00000001; // Error occured + const ERR = 0b00000001; // Error occurred const IDX = 0b00000010; // Index. Always set to zero const CORR = 0b00000100; // Corrected data. Always set to zero const DRQ = 0b00001000; // Set when the drive has PIO data to transfer, or is ready to accept PIO data @@ -118,8 +116,8 @@ bitflags::bitflags! { const DMA_ACTIVE = 0b0000_0001; const DMA_FAILED = 0b0000_0010; const DISK_IRQ = 0b0000_0100; - const MASTER_DMA_CAPPABLE = 0b0010_0000; - const SLAVE_DMA_CAPPABLE = 0b0100_0000; + const MASTER_DMA_CAPABLE = 0b0010_0000; + const SLAVE_DMA_CAPABLE = 0b0100_0000; const NO_DMA_SHARING = 0b1000_0000; } } diff --git a/src/aero_kernel/src/drivers/block/nvme/command.rs b/src/aero_kernel/src/drivers/block/nvme/command.rs index feab4bac327..120e6cce68a 100644 --- a/src/aero_kernel/src/drivers/block/nvme/command.rs +++ b/src/aero_kernel/src/drivers/block/nvme/command.rs @@ -1,23 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use bit_field::BitField; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #[repr(u8)] #[derive(Default, Copy, Clone)] @@ -41,6 +37,7 @@ bitflags::bitflags! { #[repr(u8)] #[derive(Default, Copy, Clone)] pub enum CommandOpcode { + Write = 0x1, Read = 0x2, #[default] @@ -58,7 +55,7 @@ pub enum AdminOpcode { Unknown = u8::MAX, } -#[derive(Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone)] #[repr(C)] pub struct DataPointer { pub prp1: u64, @@ -100,9 +97,9 @@ pub struct IdentifyCommand { pub reserved11: [u32; 5], } -impl Into for IdentifyCommand { - fn into(self) -> Command { - Command { identify: self } +impl From for Command { + fn from(val: IdentifyCommand) -> Self { + Command { identify: val } } } @@ -189,6 +186,7 @@ pub struct IdentifyController { pub sqes: u8, pub cqes: u8, pub maxcmd: u16, + /// This field indicates the maximum value of a valid NSID for the NVM subsystem. pub nn: u32, pub oncs: u16, pub fuses: u16, @@ -272,7 +270,7 @@ pub struct IdentifyNamespace { const_assert_eq!(core::mem::size_of::(), 0x1000); #[repr(C)] -#[derive(Default, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone)] pub struct ReadWriteCommand { pub opcode: u8, pub flags: u8, @@ -290,9 +288,9 @@ pub struct ReadWriteCommand { pub app_mask: u16, } -impl Into for ReadWriteCommand { - fn into(self) -> Command { - Command { rw: self } +impl From for Command { + fn from(val: ReadWriteCommand) -> Self { + Command { rw: val } } } @@ -312,9 +310,9 @@ pub struct CreateSQCommand { pub reserved2: [u32; 4], } -impl Into for CreateSQCommand { - fn into(self) -> Command { - Command { create_sq: self } +impl From for Command { + fn from(val: CreateSQCommand) -> Self { + Command { create_sq: val } } } @@ -334,30 +332,26 @@ pub struct CreateCQCommand { pub reserved2: [u32; 4], } -impl Into for CreateCQCommand { - fn into(self) -> Command { - Command { create_cq: self } +impl From for Command { + fn from(val: CreateCQCommand) -> Self { + Command { create_cq: val } } } #[derive(Clone, Copy, Debug)] #[repr(C)] pub struct CompletionEntry { - dw0: u32, - dw1: u32, - dw2: u32, - dw3: u32, -} - -impl CompletionEntry { - pub fn get_phase_tag(&self) -> bool { - self.dw3.get_bit(16) - } + pub result: u32, // Used by admin commands to return data. + pub reserved: u32, + pub sq_head: u16, // Portion of the queue that may be reclaimed + pub sq_id: u16, // Submission Queue that generated this entry. + pub command_id: u16, // Command ID of the command that was completed. + pub status: u16, // Reason why the command failed, if it did. } #[repr(C)] pub union Command { - common: CommonCommand, + pub(super) common: CommonCommand, identify: IdentifyCommand, rw: ReadWriteCommand, create_sq: CreateSQCommand, diff --git a/src/aero_kernel/src/drivers/block/nvme/mod.rs b/src/aero_kernel/src/drivers/block/nvme/mod.rs index 4d2d331699c..2462eedcbf9 100644 --- a/src/aero_kernel/src/drivers/block/nvme/mod.rs +++ b/src/aero_kernel/src/drivers/block/nvme/mod.rs @@ -1,29 +1,27 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . mod command; -mod dma; mod queue; +use core::mem::MaybeUninit; + use command::*; -use dma::*; -use queue::*; +use queue::QueuePair; use alloc::sync::Arc; use alloc::vec::Vec; @@ -31,11 +29,12 @@ use alloc::vec::Vec; use bit_field::BitField; use crate::arch::interrupts::{self, InterruptStack}; -use crate::drivers::pci::*; +use crate::drivers::pci::{self, *}; use crate::fs::block::{install_block_device, BlockDevice, BlockDeviceInterface}; use crate::mem::paging::*; -use crate::utils::sync::Mutex; +use crate::utils::dma::*; +use crate::utils::sync::BMutex; use crate::utils::VolatileCell; #[derive(Copy, Clone, Debug)] @@ -64,6 +63,7 @@ impl Version { } bitflags::bitflags! { + #[derive(Debug)] struct CommandSetsSupported: u8 { /// Controller supports the NVM command set. const NVM = 1 << 0; @@ -78,7 +78,8 @@ bitflags::bitflags! { struct Capability(VolatileCell); impl Capability { - /// Returns maximum individual queue size that the controller supports. + /// Returns maximum individual queue size that the controller + /// supports. fn max_queue_entries(&self) -> u16 { self.0.get().get_bits(0..16) as u16 } @@ -88,15 +89,22 @@ impl Capability { self.0.get().get_bits(32..36) } - /// Returns the command sets that are supported by the controller. + /// Returns the command sets that are supported by the + /// controller. fn get_css(&self) -> CommandSetsSupported { CommandSetsSupported::from_bits_truncate(self.0.get().get_bits(37..45) as u8) } + + /// Returns the the minimum host memory page size that the + /// controller supports. + fn mpsmin(&self) -> u64 { + self.0.get().get_bits(48..52) + } } #[repr(u32)] enum CommandSet { - NVM = 0b000, + Nvm = 0b000, } const_assert_eq!(core::mem::size_of::(), 4); @@ -136,7 +144,7 @@ impl ControllerConfig { /// Sets the command set to be used. fn set_css(&mut self, command_set: CommandSet) { // XXX: This field shall only be changed when the controller is disabled. - assert_eq!(self.is_enabled(), false); + assert!(!self.is_enabled()); let mut cfg = self.0.get(); cfg.set_bits(4..7, command_set as u32); @@ -215,36 +223,52 @@ struct Namespace<'a> { blocks: usize, block_size: usize, size: usize, + max_prps: usize, + prps: BMutex]>>, controller: Arc>, } impl<'a> Namespace<'a> { - fn read(&self, sector: usize, dest: &mut [u8]) { - let length = ((dest.len() / self.block_size) - 1) as u16; + fn rw_command(&self, opcode: CommandOpcode, sector: usize, start: PhysAddr, size_bytes: usize) { + assert!(size_bytes != 0); + + let blocks = size_bytes.div_ceil(self.block_size); + let mut read_cmd = ReadWriteCommand { + opcode: opcode as u8, + nsid: self.nsid, + start_lba: sector as u64, + length: (blocks - 1) as u16, + ..Default::default() + }; - let buffer = Dma::::new_uninit_slice(dest.len()); - let mut read_cmd = ReadWriteCommand::default(); + if size_bytes > Size4KiB::SIZE as usize { + // The data cannot fit in 8KiB frames, so we need to use + // a PRP list. + let prp_num = ((blocks - 1) * self.block_size) / Size4KiB::SIZE as usize; + assert!(prp_num < self.max_prps); - read_cmd.opcode = CommandOpcode::Read as u8; - read_cmd.nsid = self.nsid; - read_cmd.start_lba = sector as u64; - read_cmd.length = length; - read_cmd.data_ptr.prp1 = buffer.addr().as_u64(); + let mut prps = self.prps.lock(); - self.controller.io_queue.lock().submit_command(read_cmd); + for i in 0..prp_num { + prps[i].write((start.as_u64() + Size4KiB::SIZE) + (Size4KiB::SIZE * i as u64)); + } - // SAFETY: The buffer is initialized above. - let buffer = unsafe { buffer.assume_init() }; - dest.copy_from_slice(&*buffer); + read_cmd.data_ptr.prp1 = start.as_u64(); + read_cmd.data_ptr.prp2 = prps.addr().as_u64(); + } else { + read_cmd.data_ptr.prp1 = start.as_u64(); + } + + self.controller.io_queue.lock().submit_command(read_cmd); } } struct Controller<'a> { identity: Dma, - namespaces: Mutex>>, + namespaces: BMutex>>, - admin: Mutex>, - io_queue: Mutex>, + admin: BMutex>, + io_queue: BMutex>, } impl<'a> Controller<'a> { @@ -262,6 +286,8 @@ impl<'a> Controller<'a> { _ => return Err(Error::UnknownBar), }; + pci::map_bar(&bar0); + let registers = registers_addr .as_hhdm_virt() .read_mut::() @@ -294,7 +320,7 @@ impl<'a> Controller<'a> { let queue_size = registers.capability.max_queue_entries() as usize; - let mut admin = QueuePair::new(®isters, queue_size)?; + let mut admin = QueuePair::new(registers, queue_size)?; registers .aqa @@ -307,21 +333,26 @@ impl<'a> Controller<'a> { registers.acq.set(admin.completion_addr().as_u64()); // Set the controller configuration and admin queue base addresses. - registers.cc.set_css(CommandSet::NVM); + registers.cc.set_css(CommandSet::Nvm); registers.cc.set_ams(ArbitrationMechanism::RoundRobin); registers.cc.set_iosqes(6); // 64 bytes registers.cc.set_iocqes(4); // 16 bytes registers.set_enable(true)?; - let identity = Dma::::new(); - let mut identify_command = IdentifyCommand::default(); - - identify_command.opcode = AdminOpcode::Identify as u8; - identify_command.cns = IdentifyCns::Controller as u8; - identify_command.data_ptr.prp1 = identity.addr().as_u64(); - - admin.submit_command(identify_command); + let identity = Dma::::zeroed(); + + // TODO(andypython): builder pattern for building a command? We also shouldn't be required + // to manually fill in the `opcode` field. + admin.submit_command(IdentifyCommand { + opcode: AdminOpcode::Identify as u8, + cns: IdentifyCns::Controller as u8, + data_ptr: DataPointer { + prp1: identity.addr().as_u64(), + ..Default::default() + }, + ..Default::default() + }); log::trace!( "nvme: identifed controller (vendor={}, subsystem_vendor={})", @@ -330,89 +361,108 @@ impl<'a> Controller<'a> { ); // Create and initialize the I/O queues. - let io_queue = QueuePair::new(®isters, queue_size)?; - - let mut io_cq_cmd = CreateCQCommand::default(); - - io_cq_cmd.opcode = AdminOpcode::CreateCq as u8; - io_cq_cmd.prp1 = io_queue.completion_addr().as_u64(); - io_cq_cmd.cqid = io_queue.id(); - io_cq_cmd.q_size = (io_queue.len() - 1) as u16; - io_cq_cmd.irq_vector = vector as u16; - io_cq_cmd.cq_flags = - (CommandFlags::CQ_IRQ_ENABLED | CommandFlags::QUEUE_PHYS_CONTIG).bits(); - - admin.submit_command(io_cq_cmd); - - let mut io_sq_cmd = CreateSQCommand::default(); + let io_queue = QueuePair::new(registers, queue_size)?; + + admin.submit_command(CreateCQCommand { + opcode: AdminOpcode::CreateCq as u8, + prp1: io_queue.completion_addr().as_u64(), + cqid: io_queue.id(), + q_size: (io_queue.len() - 1) as u16, + irq_vector: 0, + cq_flags: CommandFlags::QUEUE_PHYS_CONTIG.bits(), + ..Default::default() + }); - io_sq_cmd.opcode = AdminOpcode::CreateSq as u8; - io_sq_cmd.prp1 = io_queue.submission_addr().as_u64(); - io_sq_cmd.cqid = io_queue.id(); - io_sq_cmd.sqid = io_queue.id(); - io_sq_cmd.q_size = (io_queue.len() - 1) as u16; - io_sq_cmd.sq_flags = - (CommandFlags::CQ_IRQ_ENABLED | CommandFlags::QUEUE_PHYS_CONTIG).bits(); + admin.submit_command(CreateSQCommand { + opcode: AdminOpcode::CreateSq as u8, + prp1: io_queue.submission_addr().as_u64(), + cqid: io_queue.id(), + sqid: io_queue.id(), + q_size: (io_queue.len() - 1) as u16, + sq_flags: CommandFlags::QUEUE_PHYS_CONTIG.bits(), + ..Default::default() + }); - admin.submit_command(io_sq_cmd); + let shift = 12 + registers.capability.mpsmin() as usize; + let max_transfer_shift = if identity.mdts != 0 { + shift + identity.mdts as usize + } else { + 20 + }; let this = Arc::new(Self { identity, - namespaces: Mutex::new(alloc::vec![]), + namespaces: BMutex::new(alloc::vec![]), - admin: Mutex::new(admin), - io_queue: Mutex::new(io_queue), + admin: BMutex::new(admin), + io_queue: BMutex::new(io_queue), }); - let namespace_ids = || { + // Discover and initialize the namespaces. + let nsids = { let nsid_list = Dma::::new_uninit_slice(this.identity.nn as usize); - let mut nsid_command = IdentifyCommand::default(); - - nsid_command.opcode = AdminOpcode::Identify as u8; - nsid_command.cns = IdentifyCns::ActivateList as u8; - nsid_command.data_ptr.prp1 = nsid_list.addr().as_u64(); - this.admin.lock().submit_command(nsid_command); + this.admin.lock().submit_command(IdentifyCommand { + opcode: AdminOpcode::Identify as u8, + cns: IdentifyCns::ActivateList as u8, + data_ptr: DataPointer { + prp1: nsid_list.addr().as_u64(), + ..Default::default() + }, + ..Default::default() + }); // SAFETY: The list is initialized above. unsafe { nsid_list.assume_init() } }; - // Discover and initialize the namespaces. - let nsids = namespace_ids(); - let namespaces = nsids - .iter() - .map(|nsid| { - let identity = Dma::::new(); - let mut identify_command = IdentifyCommand::default(); - - identify_command.opcode = AdminOpcode::Identify as u8; - identify_command.cns = IdentifyCns::Namespace as u8; - identify_command.nsid = *nsid; - identify_command.data_ptr.prp1 = identity.addr().as_u64(); - - this.admin.lock().submit_command(identify_command); - - let blocks = identity.nsze as usize; - let block_size = 1 << identity.lbaf[(identity.flbas & 0b11111) as usize].ds; - - Namespace { - controller: this.clone(), - nsid: *nsid, - blocks, - block_size, - size: blocks * block_size, - } - }) - .collect::>(); + let mut namespaces = alloc::vec![]; + + for &nsid in nsids.iter() { + // Unused entries are zero-filled. + if nsid == 0 { + continue; + } + + let identity = Dma::::zeroed(); + + this.admin.lock().submit_command(IdentifyCommand { + opcode: AdminOpcode::Identify as u8, + cns: IdentifyCns::Namespace as u8, + nsid, + data_ptr: DataPointer { + prp1: identity.addr().as_u64(), + ..Default::default() + }, + ..Default::default() + }); + + let blocks = identity.nsze as usize; + let block_size = 1 << identity.lbaf[(identity.flbas & 0b11111) as usize].ds; + + // The maximum transfer size is in units of 2^(min page size) + let lba_shift = identity.lbaf[(identity.flbas & 0xf) as usize].ds; + let max_lbas = 1 << (max_transfer_shift - lba_shift as usize); + let max_prps = (max_lbas * (1 << lba_shift)) / Size4KiB::SIZE as usize; + + let namespace = Namespace { + controller: this.clone(), + nsid, + blocks, + block_size, + size: blocks * block_size, + max_prps, + prps: BMutex::new(Dma::new_uninit_slice(max_prps)), + }; - for namespace in namespaces.iter() { log::trace!( "nvme: identified namespace (blocks={}, block_size={}, size={})", namespace.blocks, namespace.block_size, namespace.size ); + + namespaces.push(namespace); } *this.namespaces.lock() = namespaces; @@ -423,25 +473,48 @@ impl<'a> Controller<'a> { } impl<'a> BlockDeviceInterface for Controller<'a> { - fn read(&self, sector: usize, dest: &mut [u8]) -> Option { - self.namespaces.lock()[0].read(sector, dest); + fn read_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option { + self.namespaces.lock()[0].rw_command(CommandOpcode::Read, sector, start, size); + Some(size) + } + + fn write_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option { + self.namespaces.lock()[0].rw_command(CommandOpcode::Write, sector, start, size); + Some(size) + } + + fn read_block(&self, sector: usize, dest: &mut [MaybeUninit]) -> Option { + let buffer = Dma::::new_uninit_slice(dest.len()); + self.namespaces.lock()[0].rw_command( + CommandOpcode::Read, + sector, + buffer.addr(), + dest.len(), + ); + + // SAFETY: The buffer is initialized above. + dest.copy_from_slice(&buffer); Some(dest.len()) } - fn write(&self, _sector: usize, _buf: &[u8]) -> Option { + fn block_size(&self) -> usize { + self.namespaces.lock()[0].block_size + } + + fn write_block(&self, _sector: usize, _buf: &[u8]) -> Option { unimplemented!() } } // PCI device handler for NVMe controllers. struct Handler<'admin> { - controllers: Mutex>>>, + controllers: BMutex>>>, } impl<'admin> Handler<'admin> { fn new() -> Arc { Arc::new(Self { - controllers: Mutex::new(Vec::new()), + controllers: BMutex::new(Vec::new()), }) } } @@ -465,7 +538,7 @@ impl PciDeviceHandle for Handler<'static> { for device_name in devices { let device = BlockDevice::new(device_name, controller.clone()); - install_block_device(device).expect("nvme: failed to install the block device") + install_block_device(device).expect("nvme: failed to install the block device"); } self.controllers.lock().push(controller); @@ -473,12 +546,12 @@ impl PciDeviceHandle for Handler<'static> { } fn irq_handler(_stack: &mut InterruptStack) { - unimplemented!("nvme: interrupt handler!") + // unimplemented!("nvme: interrupt handler!") } fn nvme_init() { // Register the NVMe device handler. - register_device_driver(Handler::new()) + register_device_driver(Handler::new()); } -crate::module_init!(nvme_init); +crate::module_init!(nvme_init, ModuleType::Block); diff --git a/src/aero_kernel/src/drivers/block/nvme/queue.rs b/src/aero_kernel/src/drivers/block/nvme/queue.rs index 67b2baeda70..8ad65684161 100644 --- a/src/aero_kernel/src/drivers/block/nvme/queue.rs +++ b/src/aero_kernel/src/drivers/block/nvme/queue.rs @@ -1,18 +1,20 @@ -use core::mem::MaybeUninit; +use core::cell::UnsafeCell; +use core::ptr; use core::sync::atomic::{AtomicU16, Ordering}; use crate::mem::paging::PhysAddr; +use crate::utils::dma::Dma; +use crate::utils::VolatileCell; use super::command::{Command, CompletionEntry}; -use super::dma::Dma; -use super::*; +use super::{Error, Registers}; const fn calculate_doorbell_offset(queue_id: u16, multiplier: usize, dstrd: usize) -> usize { 0x1000 + ((((queue_id as usize) * 2) + multiplier) * (4 << dstrd)) } pub struct Completion; -pub struct Submisson; +pub struct Submission; pub trait QueueType { type Type; @@ -20,13 +22,15 @@ pub trait QueueType { } impl QueueType for Completion { - const DOORBELL_OFFSET: usize = 1; type Type = CompletionEntry; + + const DOORBELL_OFFSET: usize = 1; } -impl QueueType for Submisson { - const DOORBELL_OFFSET: usize = 0; +impl QueueType for Submission { type Type = Command; + + const DOORBELL_OFFSET: usize = 0; } #[repr(C)] @@ -38,7 +42,7 @@ unsafe impl Sync for DoorBell {} pub(super) struct Queue<'bell, T: QueueType> { doorbell: &'bell DoorBell, index: usize, - queue: Dma<[MaybeUninit]>, + queue: Dma<[UnsafeCell]>, phase: bool, } @@ -53,7 +57,7 @@ impl<'bell, T: QueueType> Queue<'bell, T> { Ok(Self { doorbell, - queue: Dma::new_uninit_slice(size), + queue: unsafe { Dma::new_zeroed_slice(size).assume_init() }, index: 0, phase: true, }) @@ -66,22 +70,39 @@ impl<'bell, T: QueueType> Queue<'bell, T> { impl Queue<'_, Completion> { pub fn next_cmd_result(&mut self) -> Option { - let cur_completion = unsafe { self.queue[self.index].assume_init() }; - if cur_completion.get_phase_tag() != self.phase { - self.index += 1; - self.doorbell.0.set(self.index as u32); - Some(cur_completion.clone()) - } else { - None + let queue_len = self.queue.len(); + let cmd = &mut self.queue[self.index]; + + while (cmd.get_mut().status & 0x1) != self.phase as u16 { + core::hint::spin_loop(); } + + let cmd = cmd.get_mut(); + let status = cmd.status >> 1; + + if status != 0 { + log::error!("nvme: command error {status:#x}"); + return None; + } + + self.index = (self.index + 1) % queue_len; + + // invert the phase bit since we are in the next cycle/phase. + if self.index == 0 { + self.phase = !self.phase; + } + + self.doorbell.0.set(self.index as u32); + + Some(*cmd) } } -impl Queue<'_, Submisson> { +impl Queue<'_, Submission> { pub fn submit_command(&mut self, command: Command) { - self.queue[self.index] = MaybeUninit::new(command); + self.queue[self.index] = UnsafeCell::new(command); - self.index += 1; + self.index = (self.index + 1) % self.queue.len(); self.doorbell.0.set(self.index as u32); // ring ring! } } @@ -92,25 +113,39 @@ pub(super) struct QueuePair<'a> { id: u16, size: usize, - submission: Queue<'a, Submisson>, + cid: u16, + + submission: Queue<'a, Submission>, completion: Queue<'a, Completion>, } impl<'a> QueuePair<'a> { pub fn new(registers: &Registers, size: usize) -> Result { - let queue_id = QUEUE_PAIR_ID.fetch_add(2, Ordering::SeqCst); + let queue_id = QUEUE_PAIR_ID.fetch_add(1, Ordering::SeqCst); Ok(Self { size, id: queue_id, + cid: 0, + submission: Queue::new(registers, size, queue_id)?, completion: Queue::new(registers, size, queue_id)?, }) } pub fn submit_command>(&mut self, command: T) { - self.submission.submit_command(command.into()); + let mut command = command.into(); + + unsafe { + // SAFETY: The offset of the `command_id` field is the same, regardless of the command + // type. + *ptr::addr_of_mut!(command).cast::().add(1) = self.cid; + } + + self.cid += 1; + + self.submission.submit_command(command); self.completion.next_cmd_result().unwrap(); } diff --git a/src/aero_kernel/src/drivers/drm/mod.rs b/src/aero_kernel/src/drivers/drm/mod.rs index 36e4f23aa99..2cbfbb7e35e 100644 --- a/src/aero_kernel/src/drivers/drm/mod.rs +++ b/src/aero_kernel/src/drivers/drm/mod.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . mod rawfb; @@ -26,10 +24,10 @@ use alloc::vec::Vec; use bit_field::BitField; use hashbrown::HashMap; +use crate::arch::user_copy::UserRef; use crate::fs; -use crate::fs::devfs; use crate::fs::inode::INodeInterface; -use crate::fs::FileSystemError; +use crate::fs::{devfs, FileSystemError}; use crate::mem::paging::*; use crate::utils::sync::Mutex; @@ -75,14 +73,14 @@ trait DrmDevice: Send + Sync { fn framebuffer_create(&self, buffer_object: &BufferObject, width: u32, height: u32, pitch: u32); fn commit(&self, buffer_obj: &BufferObject); - /// Returns tuple containing the minumum dimensions (`xmin`, `ymin`). + /// Returns tuple containing the minimum dimensions (`xmin`, `ymin`). fn min_dim(&self) -> (usize, usize); - /// Returns tuple containing the miximum dimensions (`xmax`, `ymax`). + /// Returns tuple containing the maximum dimensions (`xmax`, `ymax`). fn max_dim(&self) -> (usize, usize); - /// Returns a tuple containg the driver major, minor and patch level respectively. + /// Returns a tuple containing the driver major, minor and patch level respectively. fn driver_version(&self) -> (usize, usize, usize); - /// Returns a tuple contaning the driver name, desc and date respectively. + /// Returns a tuple containing the driver name, desc and date respectively. fn driver_info(&self) -> (&'static str, &'static str, &'static str); } @@ -114,8 +112,7 @@ impl BufferObject { // - has the display mode and params. // // Encoders: -// - takes the raw data from the CRTCs and converts it into a -// specific format. +// - takes the raw data from the CRTCs and converts it into a specific format. // // Connectors: // - outputs the encoded data to an external display. @@ -149,7 +146,7 @@ impl ModeObject for Crtc { } fn object(&self) -> Arc { - self.sref.upgrade().unwrap().clone() + self.sref.upgrade().unwrap() } } @@ -158,9 +155,9 @@ struct Encoder { /// The current CRTC for this encoder. current_crtc: Arc, - /// A vector contaning all the possible CRTCs for this encoder. + /// A vector containing all the possible CRTCs for this encoder. possible_crtcs: Vec>, - /// A vector contaning all the possible sibling encoders for cloning. + /// A vector containing all the possible sibling encoders for cloning. possible_clones: Vec>, object_id: u32, @@ -193,7 +190,7 @@ impl ModeObject for Encoder { } fn object(&self) -> Arc { - self.sref.upgrade().unwrap().clone() + self.sref.upgrade().unwrap() } } @@ -206,9 +203,9 @@ struct Connector { status: DrmModeConStatus, /// The current encoder for this connector. current_encoder: Arc, - /// A vector contaning all the possible encoders for this connector. + /// A vector containing all the possible encoders for this connector. possible_encoders: Vec>, - /// A vector contaning all of the possible display modes for this connector. + /// A vector containing all of the possible display modes for this connector. modes: Vec, connector_typ: u32, @@ -242,7 +239,7 @@ impl ModeObject for Connector { } fn object(&self) -> Arc { - self.sref.upgrade().unwrap().clone() + self.sref.upgrade().unwrap() } } @@ -270,7 +267,7 @@ impl ModeObject for Framebuffer { } fn object(&self) -> Arc { - self.sref.upgrade().unwrap().clone() + self.sref.upgrade().unwrap() } } @@ -409,7 +406,7 @@ impl INodeInterface for Drm { fn ioctl(&self, command: usize, arg: usize) -> fs::Result { match command { DRM_IOCTL_VERSION => { - let struc = VirtAddr::new(arg as u64).read_mut::().unwrap(); + let mut struc = unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let (major, minor, patch_level) = self.device.driver_version(); let (name, desc, date) = self.device.driver_info(); @@ -426,7 +423,7 @@ impl INodeInterface for Drm { } DRM_IOCTL_GET_CAP => { - let struc = VirtAddr::new(arg as u64).read_mut::().unwrap(); + let mut struc = unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; // NOTE: The user is responsible for zeroing out the structure. match struc.capability { @@ -446,11 +443,10 @@ impl INodeInterface for Drm { } DRM_IOCTL_MODE_GETRESOURCES => { - let struc = VirtAddr::new(arg as u64) - .read_mut::() - .unwrap(); + let mut struc = + unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; - /// Copies the mode object IDs into the user provided buffer. For saftey, checkout + /// Copies the mode object IDs into the user provided buffer. For safety, checkout /// the [`copy_field`] function. fn copy_mode_obj_id( obj: &Mutex>>, @@ -493,7 +489,7 @@ impl INodeInterface for Drm { } DRM_IOCTL_GET_CRTC => { - let struc = VirtAddr::new(arg as u64).read_mut::().unwrap(); + let struc = unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let _object = self.find_object(struc.crtc_id).unwrap().as_crtc().unwrap(); log::warn!("drm::get_crtc: is a stub!"); @@ -501,7 +497,7 @@ impl INodeInterface for Drm { } DRM_IOCTL_SET_CRTC => { - let struc = VirtAddr::new(arg as u64).read_mut::().unwrap(); + let struc = unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let _object = self.find_object(struc.crtc_id).unwrap().as_crtc().unwrap(); let object = self @@ -517,9 +513,8 @@ impl INodeInterface for Drm { } DRM_IOCTL_GET_ENCODER => { - let struc = VirtAddr::new(arg as u64) - .read_mut::() - .unwrap(); + let mut struc = + unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let object = self .find_object(struc.encoder_id) @@ -548,9 +543,8 @@ impl INodeInterface for Drm { } DRM_IOCTL_GET_CONNECTOR => { - let struc = VirtAddr::new(arg as u64) - .read_mut::() - .unwrap(); + let mut struc = + unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let object = self .find_object(struc.connector_id) @@ -558,7 +552,7 @@ impl INodeInterface for Drm { .as_connector() .unwrap(); - // Fill in the array contaning all of the possible encoders and its length. + // Fill in the array containing all of the possible encoders and its length. let encoder_ids_ptr = struc.encoders_ptr as *mut u32; let mut encoder_count = 0; @@ -585,7 +579,7 @@ impl INodeInterface for Drm { struc.mm_height = 0; // todo struc.subpixel = 0; // todo - // Fill in the array contaning all of the possible modes and its length. + // Fill in the array containing all of the possible modes and its length. let modes_ptr = struc.modes_ptr as *mut DrmModeInfo; let mut modes_count = 0; @@ -596,9 +590,8 @@ impl INodeInterface for Drm { } DRM_IOCTL_MODE_CREATE_DUMB => { - let struc = VirtAddr::new(arg as u64) - .read_mut::() - .unwrap(); + let mut struc = + unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let (mut buffer, pitch) = self.device @@ -616,15 +609,13 @@ impl INodeInterface for Drm { } DRM_IOCTL_MODE_ADDFB => { - let struc = VirtAddr::new(arg as u64) - .read_mut::() - .unwrap(); + let mut struc = unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let handle = self.find_handle(struc.handle).unwrap(); self.device .framebuffer_create(&handle, struc.width, struc.height, struc.pitch); - let fb = Framebuffer::new(self.allocate_object_id(), handle.clone()); + let fb = Framebuffer::new(self.allocate_object_id(), handle); self.install_framebuffer(fb.clone()); struc.fb_id = fb.id(); @@ -632,9 +623,8 @@ impl INodeInterface for Drm { } DRM_IOCTL_MODE_MAP_DUMB => { - let struc = VirtAddr::new(arg as u64) - .read_mut::() - .unwrap(); + let mut struc = + unsafe { UserRef::::new(VirtAddr::new(arg as u64)) }; let handle = self.find_handle(struc.handle).unwrap(); struc.offset = handle.mapping as _; @@ -1093,8 +1083,8 @@ fn make_dmt_modes(max_width: u16, max_height: u16) -> Vec { // Sort the modes by display size: result.sort_by(|e, f| { - (e.hdisplay * e.vdisplay) - .partial_cmp(&(f.hdisplay * f.vdisplay)) + ((e.hdisplay as usize) * (e.vdisplay as usize)) + .partial_cmp(&((f.hdisplay as usize) * (f.vdisplay as usize))) .unwrap() // unreachable }); diff --git a/src/aero_kernel/src/drivers/drm/rawfb.rs b/src/aero_kernel/src/drivers/drm/rawfb.rs index a6be41ab4e6..1020539df8b 100644 --- a/src/aero_kernel/src/drivers/drm/rawfb.rs +++ b/src/aero_kernel/src/drivers/drm/rawfb.rs @@ -1,30 +1,28 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::sync::Arc; +use uapi::drm::DrmModeConStatus; -use crate::fs::devfs; -use crate::fs::FileSystem; +use crate::fs::{devfs, FileSystem}; use crate::mem::paging::*; -use super::*; +use super::{make_dmt_modes, BufferObject, Connector, Crtc, Drm, DrmDevice, Encoder}; use crate::rendy; struct RawFramebuffer {} @@ -57,7 +55,7 @@ impl DrmDevice for RawFramebuffer { unsafe { core::ptr::copy_nonoverlapping( frame.as_slice_mut::().as_mut_ptr(), - (fb.as_mut_ptr() as *mut u8) + (fb.as_mut_ptr().cast::()) .offset(i as isize * Size4KiB::SIZE as isize), 4096, ) @@ -134,4 +132,4 @@ fn init() { devfs::install_device_at(dri, rfb).expect("ramfs: failed to install DRM device"); } -crate::module_init!(init); +crate::module_init!(init, ModuleType::Block); diff --git a/src/aero_kernel/src/drivers/e1000.rs b/src/aero_kernel/src/drivers/e1000.rs new file mode 100644 index 00000000000..3c1dca5c2c5 --- /dev/null +++ b/src/aero_kernel/src/drivers/e1000.rs @@ -0,0 +1,668 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::ptr; + +use alloc::boxed::Box; +use alloc::sync::Arc; +use spin::Once; + +use crate::acpi::aml; +use crate::arch::interrupts::{self, InterruptStack}; +use crate::drivers::pci::*; +use crate::mem::paging::*; +use crate::userland::scheduler; +use crate::utils::dma::DmaAllocator; +use crate::utils::sync::{Mutex, WaitQueue}; + +use crate::net::{self, NetworkDevice, NetworkDriver}; +use crabnet::data_link::MacAddr; + +const TX_DESC_NUM: u32 = 32; +const TX_DESC_SIZE: u32 = TX_DESC_NUM * core::mem::size_of::() as u32; + +const RX_DESC_NUM: u32 = 32; +const RX_DESC_SIZE: u32 = RX_DESC_NUM * core::mem::size_of::() as u32; + +#[derive(Copy, Clone, Debug)] +enum Error { + UnknownBar, + NoEeprom, + OutOfMemory, + ReadErr(ReadErr), +} + +impl From for Error { + fn from(value: ReadErr) -> Self { + Self::ReadErr(value) + } +} + +#[derive(Copy, Clone)] +#[repr(usize)] +enum Register { + Control = 0x0, + Status = 0x8, + + Eeprom = 0x14, + + ICause = 0xc0, + IRate = 0xc4, + IMask = 0xd0, + + RCtrl = 0x100, + /// Lower bits of the 64 bit descriptor base address. + RxDescLo = 0x2800, + /// Upper 32 bits of the 64 bit descriptor base address. + RxDescHi = 0x2804, + /// Descriptor length and must be 128B aligned. + RxDescLen = 0x2808, + /// Head pointer for the receive descriptor buffer. + RxDescHead = 0x2810, + /// Tail pointer for the receive descriptor buffer. + RxDescTail = 0x2818, + + TCtrl = 0x400, + /// Lower bits of the 64 bit descriptor base address. + TxDesLo = 0x3800, + /// Upper 32 bits of the 64 bit descriptor base address. + TxDesHi = 0x3804, + /// Descriptor length and must be 128B aligned. + TxDescLen = 0x3808, + /// Head pointer for the transmit descriptor ring. + TxDescHead = 0x3810, + /// Tail pointer for the transmit descriptor ring. + TxDescTail = 0x3818, + /// Controls the IPG (Inter Packet Gap) timer. + Tipg = 0x410, +} + +bitflags::bitflags! { + struct ControlFlags: u32 { + const LRST = 1 << 3; + const ASDE = 1 << 5; + const SLU = 1 << 6; + const ILOS = 1 << 7; + const RST = 1 << 26; + const VME = 1 << 30; + const PHY_RST = 1 << 31; + } +} + +bitflags::bitflags! { + #[derive(Default)] + struct TStatus: u8 { + const DD = 1 << 0; // Descriptor Done + const EC = 1 << 1; // Excess Collisions + const LC = 1 << 2; // Late Collision + const TU = 1 << 3; // Transmit Underrun + } +} + +bitflags::bitflags! { + struct ECtl: u32 { + const LRST = 1 << 3; + const ASDE = 1 << 5; + const SLU = 1 << 6; // Set Link Up + const ILOS = 1 << 7; + const RST = 1 << 26; + const VME = 1 << 30; + const PHY_RST = 1 << 31; + } +} + +struct TCtl(u32); + +bitflags::bitflags! { + impl TCtl: u32 { + const EN = 1 << 1; // Transmit Enable + const PSP = 1 << 3; // Pad Short Packets + const SWXOFF = 1 << 22; // Software XOFF Transmission + const RTLC = 1 << 24; // Re-transmit on Late Collision + } +} + +impl TCtl { + /// Sets the number of attempts at retransmission prior to giving + /// up on the packet (not including the first transmission attempt). + fn set_collision_threshold(&mut self, value: u8) { + self.0 |= (value as u32) << 4; + } + + /// Sets the minimum number of byte times which must elapse for + /// proper CSMA/CD operation. + fn set_collision_distance(&mut self, value: u8) { + self.0 |= (value as u32) << 12; + } +} + +bitflags::bitflags! { + struct RCtl: u32 { + const EN = 1 << 1; // Receiver Enable + const SBP = 1 << 2; // Store Bad Packets + const UPE = 1 << 3; // Unicast Promiscuous Enabled + const MPE = 1 << 4; // Multicast Promiscuous Enabled + const LPE = 1 << 5; // Long Packet Reception Enable + const LBM_NONE = 0 << 6; // No Loopback + const LBM_PHY = 3 << 6; // PHY or external SerDesc loopback + const RDMTS_HALF = 0 << 8; // Free Buffer Threshold is 1/2 of RDLEN + const RDMTS_QUARTER = 1 << 8; // Free Buffer Threshold is 1/4 of RDLEN + const RDMTS_EIGHTH = 2 << 8; // Free Buffer Threshold is 1/8 of RDLEN + // const MO_36 = 0 << 12; // Multicast Offset - bits 47:36 + const MO_35 = 1 << 12; // Multicast Offset - bits 46:35 + const MO_34 = 2 << 12; // Multicast Offset - bits 45:34 + const MO_32 = 3 << 12; // Multicast Offset - bits 43:32 + const BAM = 1 << 15; // Broadcast Accept Mode + const VFE = 1 << 18; // VLAN Filter Enable + const CFIEN = 1 << 19; // Canonical Form Indicator Enable + const CFI = 1 << 20; // Canonical Form Indicator Bit Value + const DPF = 1 << 22; // Discard Pause Frames + const PMCF = 1 << 23; // Pass MAC Control Frames + const SECRC = 1 << 26; // Strip Ethernet CRC + + // Receive Buffer Size - bits 17:16 + const BSIZE_256 = 3 << 16; + const BSIZE_512 = 2 << 16; + const BSIZE_1024 = 1 << 16; + // const BSIZE_2048 = 0 << 16; + const BSIZE_4096 = (3 << 16) | (1 << 25); + const BSIZE_8192 = (2 << 16) | (1 << 25); + const BSIZE_16384 = (1 << 16) | (1 << 25); + } +} + +bitflags::bitflags! { + pub struct InterruptFlags: u32 { + const TXDW = 1 << 0; // Transmit Descriptor Written Back + const TXQE = 1 << 1; // Transmit Queue Empty + const LSC = 1 << 2; // Link Status Change + const RXDMT0 = 1 << 4; // Receive Descriptor Minimum Threshold + const DSW = 1 << 5; // Disable SW Write Access + const RXO = 1 << 6; // Receiver Overrun + const RXT0 = 1 << 7; // Receiver Timer Interrupt + const MDAC = 1 << 9; // MDIO Access Complete + const PHYINT = 1 << 12; // PHY Interrupt + const LSECPN = 1 << 14; // MACsec Packet Number + const TXD_LOW = 1 << 15; // Transmit Descriptor Low Threshold hit + const SRPD = 1 << 16; // Small Receive Packet Detected + const ACK = 1 << 17; // Receive ACK Frame Detected + const ECCER = 1 << 22; // ECC Error + } +} + +#[derive(Default)] +#[repr(C, packed)] +struct TxDescriptor { + pub addr: u64, + pub length: u16, + pub cso: u8, + pub cmd: u8, + pub status: TStatus, + pub css: u8, + pub special: u16, +} + +#[derive(Default)] +#[repr(C, packed)] +struct RxDescriptor { + pub addr: u64, + pub length: u16, + pub checksum: u16, + pub status: u8, + pub errors: u8, + pub special: u16, +} + +struct Eeprom<'a> { + e1000: &'a E1000, +} + +impl<'a> Eeprom<'a> { + fn new(e1000: &'a E1000) -> Self { + Self { e1000 } + } + + fn read(&self, addr: u8) -> u32 { + self.e1000.write(Register::Eeprom, 1 | ((addr as u32) << 8)); + + loop { + let res = self.e1000.read(Register::Eeprom); + + if res & (1 << 4) > 0 { + return (res >> 16) & 0xffff; + } + } + } +} + +struct E1000 { + base: VirtAddr, + mac: MacAddr, + + tx_cur: usize, + tx_ring: VirtAddr, + + rx_cur: usize, + rx_ring: VirtAddr, +} + +impl E1000 { + fn new(header: &PciHeader) -> Result { + header.enable_bus_mastering(); + header.enable_mmio(); + + let bar0 = header.get_bar(0).ok_or(Error::UnknownBar)?; + + let registers_addr = match bar0 { + Bar::Memory64 { address, .. } => PhysAddr::new(address), + Bar::Memory32 { address, .. } => PhysAddr::new(address as u64), + _ => return Err(Error::UnknownBar), + }; + + let mut this = Self { + base: registers_addr.as_hhdm_virt(), + mac: MacAddr([0; 6]), + + tx_cur: 0, + tx_ring: VirtAddr::zero(), + + rx_cur: 0, + rx_ring: VirtAddr::zero(), + }; + + this.reset(); + + if !this.detect_eeprom() { + return Err(Error::NoEeprom); + } + + let eeprom = Eeprom::new(&this); + + let mut mac = [0u8; 6]; + + // Get the MAC address + for i in 0..3 { + let x = eeprom.read(i) as u16; + mac[i as usize * 2] = (x & 0xff) as u8; + mac[i as usize * 2 + 1] = (x >> 8) as u8; + } + + log::trace!( + "e1000: MAC address {:x}:{:x}:{:x}:{:x}:{:x}:{:x}", + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] + ); + + this.mac = MacAddr(mac); + + this.init_tx()?; + this.init_rx()?; + + // XXX: The e1000 does not support MSIx and MSI. + let gsi = aml::get_subsystem().pci_route_pin( + 0, + header.bus(), + header.device(), + header.function(), + header.interrupt_pin(), + ); + + let vector = interrupts::allocate_vector(); + interrupts::register_handler(vector, irq_handler); + + crate::arch::apic::io_apic_setup_legacy_irq(gsi, vector, 0); + + // Clear statistical counters. + for i in 0..128 { + unsafe { + this.write_raw(0x5200 + i * 4, 0); + } + } + + // Enable interrupts! + this.write( + Register::IMask, + (InterruptFlags::TXDW + | InterruptFlags::TXQE + | InterruptFlags::LSC + | InterruptFlags::RXDMT0 + | InterruptFlags::DSW + | InterruptFlags::RXO + | InterruptFlags::RXT0 + | InterruptFlags::MDAC + | InterruptFlags::PHYINT + | InterruptFlags::LSECPN + | InterruptFlags::TXD_LOW + | InterruptFlags::SRPD + | InterruptFlags::ACK + | InterruptFlags::ECCER) + .bits(), + ); + this.read(Register::ICause); + + this.link_up(); + + log::trace!("e1000: successfully initialized"); + Ok(this) + } + + fn handle_irq(&mut self) { + let cause = self.read(Register::ICause); + log::debug!("cause: {cause}"); + if cause & 0x80 != 0x80 { + return; + } + + let idx = self.rx_cur; + let descriptor = &self.rx_ring()[idx]; + log::debug!("{}", descriptor.status); + + if descriptor.status & 0x1 == 0x1 { + // we got some packies right here mate. lets notify the boyz + DEVICE.get().unwrap().wq.notify_all(); + } + } + + fn send(&mut self, packet: Box<[u8], DmaAllocator>) { + let cur = self.tx_cur; + let ring = self.tx_ring(); + + ring[cur].addr = + unsafe { VirtAddr::new(packet.as_ptr() as u64) - crate::PHYSICAL_MEMORY_OFFSET }; + ring[cur].length = packet.len() as _; + ring[cur].cmd = 0b1011; + ring[cur].status = TStatus::empty(); + + self.tx_cur = (self.tx_cur + 1) % TX_DESC_NUM as usize; + + self.write(Register::TxDescTail, self.tx_cur as u32); + core::mem::forget(packet); // FIXME: hack + } + + fn recv<'a>(&mut self) -> Option> { + let id = self.rx_cur; + let desc = &mut self.rx_ring()[id]; + + if desc.status & 0x1 != 0x1 { + return None; + } + + let packet = PhysAddr::new(desc.addr) + .as_hhdm_virt() + .as_bytes_mut(desc.length as usize); + + Some(net::RecvPacket { packet, id }) + } + + fn recv_end(&mut self, id: usize) { + let desc = &mut self.rx_ring()[id]; + + if desc.status & 0x1 != 0x1 { + unreachable!() + } + + desc.status = 0; + + let old = self.rx_cur; + self.rx_cur = (self.rx_cur + 1) % RX_DESC_NUM as usize; + self.write(Register::RxDescTail, old as u32); + } + + fn link_up(&self) { + self.insert_flags(Register::Control, ECtl::SLU.bits()); + + while self.read(Register::Status) & 2 != 2 { + core::hint::spin_loop(); + } + } + + fn rx_ring(&mut self) -> &mut [RxDescriptor] { + self.rx_ring + .read_mut::<[RxDescriptor; RX_DESC_NUM as usize]>() + .unwrap() + } + + fn tx_ring(&mut self) -> &mut [TxDescriptor] { + self.tx_ring + .read_mut::<[TxDescriptor; TX_DESC_NUM as usize]>() + .unwrap() + } + + fn init_tx(&mut self) -> Result<(), Error> { + assert!(TX_DESC_SIZE < Size4KiB::SIZE as u32); + + let frame: PhysFrame = + FRAME_ALLOCATOR.allocate_frame().ok_or(Error::OutOfMemory)?; + + let phys = frame.start_address(); + let addr = phys.as_hhdm_virt(); + + let descriptors = addr.read_mut::<[TxDescriptor; TX_DESC_NUM as usize]>()?; + + for desc in descriptors { + *desc = TxDescriptor::default(); + desc.status = TStatus::DD; + } + + self.tx_ring = addr; + + self.write(Register::TxDesLo, phys.as_u64() as _); + self.write(Register::TxDesHi, (phys.as_u64() >> 32) as _); + self.write(Register::TxDescLen, TX_DESC_SIZE); + self.write(Register::TxDescHead, 0); + self.write(Register::TxDescTail, 0); + + let mut flags = TCtl(1 << 28) | TCtl::EN | TCtl::PSP | TCtl::RTLC; + flags.set_collision_distance(64); + flags.set_collision_threshold(15); + + self.write(Register::TCtrl, flags.bits()); + + // TODO: Set the default values for the Tx Inter Packet + // Gap Timer. + // self.write(Register::Tipg, 0x???????); + + Ok(()) + } + + fn init_rx(&mut self) -> Result<(), Error> { + assert!(TX_DESC_SIZE < Size4KiB::SIZE as u32); + + let frame: PhysFrame = + FRAME_ALLOCATOR.allocate_frame().ok_or(Error::OutOfMemory)?; + + let phys = frame.start_address(); + let addr = phys.as_hhdm_virt(); + + let descriptors = addr.read_mut::<[RxDescriptor; RX_DESC_NUM as usize]>()?; + + for desc in descriptors { + let frame: PhysFrame = + FRAME_ALLOCATOR.allocate_frame().ok_or(Error::OutOfMemory)?; + + *desc = RxDescriptor::default(); + desc.addr = frame.start_address().as_u64(); + } + + self.rx_ring = addr; + + self.write(Register::RxDescLo, phys.as_u64() as _); + self.write(Register::RxDescHi, (phys.as_u64() >> 32) as _); + self.write(Register::RxDescLen, RX_DESC_SIZE); + self.write(Register::RxDescHead, 0); + self.write(Register::RxDescTail, RX_DESC_NUM - 1); + + let flags = RCtl::EN + | RCtl::UPE + | RCtl::LPE + | RCtl::MPE + | RCtl::LBM_NONE + | RCtl::RDMTS_EIGHTH + | RCtl::BAM + | RCtl::SECRC + | RCtl::BSIZE_4096; + + self.write(Register::RCtrl, flags.bits()); + Ok(()) + } + + fn detect_eeprom(&self) -> bool { + self.write(Register::Eeprom, 1); + + for _ in 0..1000 { + let value = self.read(Register::Eeprom); + + if value & (1 << 4) > 0 { + return true; + } + } + + false + } + + fn reset(&self) { + self.insert_flags(Register::Control, ControlFlags::RST.bits()); + + while ControlFlags::from_bits_truncate(self.read(Register::Control)) + .contains(ControlFlags::RST) + { + core::hint::spin_loop(); + } + + // Do not use VLANs, clear reset and do not invert loss-of-signal. + self.remove_flags( + Register::Control, + (ControlFlags::LRST | ControlFlags::PHY_RST | ControlFlags::VME).bits(), + ); + } + + fn remove_flags(&self, register: Register, flag: u32) { + self.write(register, self.read(register) & !flag); + } + + fn insert_flags(&self, register: Register, flag: u32) { + self.write(register, self.read(register) | flag); + } + + fn write(&self, register: Register, value: u32) { + unsafe { self.write_raw(register as u32, value) } + } + + fn read(&self, register: Register) -> u32 { + unsafe { self.read_raw(register as u32) } + } + + unsafe fn write_raw(&self, register: u32, value: u32) { + unsafe { + let register = self.base.as_mut_ptr::().byte_add(register as usize); + ptr::write_volatile(register, value); + } + } + + unsafe fn read_raw(&self, register: u32) -> u32 { + let register = self.base.as_ptr::().byte_add(register as usize); + ptr::read_volatile(register) + } +} + +struct Device { + e1000: Mutex, + wq: WaitQueue, +} + +impl Device { + fn new(e1000: E1000) -> Self { + Self { + e1000: Mutex::new(e1000), + wq: WaitQueue::new(), + } + } + + fn handle_irq(&self) { + self.e1000.lock_irq().handle_irq() + } +} + +impl NetworkDriver for Device { + fn send(&self, packet: Box<[u8], DmaAllocator>) { + self.e1000.lock_irq().send(packet) + } + + fn recv(&self) -> net::RecvPacket { + let task = scheduler::get_scheduler().current_task(); + self.wq.insert(task.clone()); + + loop { + let mut e1000 = self.e1000.lock_irq(); + if let Some(data) = e1000.recv() { + self.wq.remove(&task); + return data; + } else { + drop(e1000); + scheduler::get_scheduler().await_io().unwrap(); + } + } + } + + fn recv_end(&self, packet_id: usize) { + self.e1000.lock_irq().recv_end(packet_id) + } + + fn mac(&self) -> MacAddr { + self.e1000.lock_irq().mac + } +} + +struct Handler; + +impl Handler { + fn new() -> Arc { + Arc::new(Self {}) + } +} + +impl PciDeviceHandle for Handler { + fn handles(&self, vendor_id: Vendor, device_id: DeviceType) -> bool { + vendor_id == Vendor::Intel && device_id == DeviceType::EthernetController + } + + fn start(&self, header: &PciHeader, _offset_table: &mut OffsetPageTable) { + let e1000 = E1000::new(header).unwrap(); + let device = Arc::new(Device::new(e1000)); + + DEVICE.call_once(|| device.clone()); + net::add_device(NetworkDevice::new(device)); + } +} + +static DEVICE: Once> = Once::new(); + +fn irq_handler(_stack: &mut InterruptStack) { + if let Some(e) = DEVICE.get() { + e.handle_irq() + } +} + +fn init() { + register_device_driver(Handler::new()) +} + +crate::module_init!(init, ModuleType::Block); diff --git a/src/aero_kernel/src/drivers/gdbstub.rs b/src/aero_kernel/src/drivers/gdbstub.rs new file mode 100644 index 00000000000..1e82aea22b1 --- /dev/null +++ b/src/aero_kernel/src/drivers/gdbstub.rs @@ -0,0 +1,4 @@ +// TODO: Is it worth adding a GDB stub to facilitate userland debugging? +pub fn init() {} + +crate::module_init!(init, ModuleType::Other); diff --git a/src/aero_kernel/src/drivers/keyboard.rs b/src/aero_kernel/src/drivers/keyboard.rs index 7c7e4ee0403..2379c934b3a 100644 --- a/src/aero_kernel/src/drivers/keyboard.rs +++ b/src/aero_kernel/src/drivers/keyboard.rs @@ -1,22 +1,21 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::OpenFlags; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; use spin::RwLock; @@ -26,15 +25,15 @@ use crate::fs; use crate::arch::{apic, io}; use crate::fs::devfs::{self, Device}; -use crate::fs::inode::INodeInterface; -use crate::utils::sync::Mutex; +use crate::fs::inode::{INodeInterface, PollFlags}; +use crate::utils::sync::{Mutex, WaitQueue}; pub trait KeyboardListener: Send + Sync { fn on_key(&self, key: KeyCode, released: bool); } static PS2_KEYBOARD_STATE: Mutex = Mutex::new(Ps2KeyboardState::new()); -static KEYBOARD_LISTNER: RwLock> = RwLock::new(Vec::new()); +static KEYBOARD_LISTENER: RwLock>> = RwLock::new(Vec::new()); struct Ps2KeyboardState { special: bool, @@ -189,6 +188,7 @@ struct KeyboardDevice { marker: usize, buffer: Mutex>, sref: Weak, + wq: WaitQueue, } impl KeyboardDevice { @@ -197,6 +197,7 @@ impl KeyboardDevice { marker: devfs::alloc_device_marker(), buffer: Mutex::new(Vec::new()), sref: this.clone(), + wq: WaitQueue::new(), }) } } @@ -222,11 +223,18 @@ impl KeyboardListener for KeyboardDevice { } else { self.buffer.lock_irq().push(keycode as u8); } + + self.wq.notify_all() } } impl INodeInterface for KeyboardDevice { - fn read_at(&self, _offset: usize, buffer: &mut [u8]) -> fs::Result { + fn read_at(&self, _flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> fs::Result { + if self.buffer.lock_irq().is_empty() { + return Ok(0); + } + + // TODO: block using wq let mut sbuf = self.buffer.lock_irq(); let drainage = core::cmp::min(buffer.len(), sbuf.len()); @@ -236,6 +244,18 @@ impl INodeInterface for KeyboardDevice { Ok(drainage) } + + fn poll(&self, table: Option<&mut fs::inode::PollTable>) -> fs::Result { + if let Some(q) = table { + q.insert(&self.wq) + } + + if !self.buffer.lock_irq().is_empty() { + Ok(PollFlags::IN) + } else { + Ok(PollFlags::empty()) + } + } } /// This function is responsible for initializing PS2 keyboard driver. @@ -261,9 +281,9 @@ pub fn ps2_keyboard_init() { let mut config = ConfigFlags::from_bits_truncate(io::inb(0x60)); - config.remove(ConfigFlags::FIRST_DISABLED); + config.remove(ConfigFlags::FIRST_DISABLED | ConfigFlags::SECOND_DISABLED); config.remove(ConfigFlags::FIRST_TRANSLATE); // Use scancode set 2 - config.insert(ConfigFlags::FIRST_INTERRUPT); + config.insert(ConfigFlags::FIRST_INTERRUPT | ConfigFlags::SECOND_INTERRUPT); io::outb(0x64, 0x60); // command: write config io::outb(0x60, config.bits()); @@ -276,14 +296,16 @@ pub fn ps2_keyboard_init() { apic::io_apic_setup_legacy_irq(1, keyboard_vector, 1); + super::mouse::ps2_mouse_init(); + // TODO: Move this into /dev/input instead // TODO: Add support for multiple keyboards - register_keyboard_listener(KEYBOARD.as_ref().clone()); + register_keyboard_listener(KEYBOARD.clone()); devfs::install_device(KEYBOARD.clone()).expect("failed to install keyboard device"); } -pub fn register_keyboard_listener(listner: &'static dyn KeyboardListener) { - KEYBOARD_LISTNER.write().push(listner) +pub fn register_keyboard_listener(listener: Arc) { + KEYBOARD_LISTENER.write().push(listener) } pub fn keyboard_irq_handler(_stack: &mut InterruptStack) { @@ -414,12 +436,12 @@ pub fn keyboard_irq_handler(_stack: &mut InterruptStack) { core::mem::drop(lock); - let listners = KEYBOARD_LISTNER.read(); - for listener in listners.iter() { + let listeners = KEYBOARD_LISTENER.read(); + for listener in listeners.iter() { listener.on_key(keycode, released); } } } } -crate::module_init!(ps2_keyboard_init); +crate::module_init!(ps2_keyboard_init, ModuleType::Other); diff --git a/src/aero_kernel/src/drivers/lai.rs b/src/aero_kernel/src/drivers/lai.rs index d3b0f7639a9..1d67c694d0b 100644 --- a/src/aero_kernel/src/drivers/lai.rs +++ b/src/aero_kernel/src/drivers/lai.rs @@ -1,27 +1,23 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::sync::Arc; -use crate::acpi::aml; -use crate::acpi::fadt; -use crate::acpi::get_acpi_table; +use crate::acpi::{aml, fadt, get_acpi_table}; use crate::mem::paging::PhysAddr; @@ -34,20 +30,20 @@ struct LaiHost; impl lai::Host for LaiHost { fn scan(&self, signature: &str, index: usize) -> *const u8 { - assert!(index == 0); - if signature == "DSDT" { // The DSDT table is put inside the FADT table, instead of listing it in // another ACPI table. So, we need to extract the DSDT table from the FADT // table. - get_acpi_table().lookup_entry(fadt::SIGNATURE).map(|fadt| { - let fadt: &'static fadt::Fadt = unsafe { fadt.as_ref() }; - let addr = PhysAddr::new(fadt.dsdt as u64).as_hhdm_virt(); - addr.as_ptr::() - }) + get_acpi_table() + .lookup_entry(fadt::SIGNATURE, 0) + .map(|fadt| { + let fadt: &'static fadt::Fadt = unsafe { fadt.as_ref() }; + let addr = PhysAddr::new(fadt.dsdt as u64).as_hhdm_virt(); + addr.as_ptr::() + }) } else { get_acpi_table() - .lookup_entry(signature) + .lookup_entry(signature, index) .map(|table| table as *const _ as *const u8) } .unwrap_or(core::ptr::null()) @@ -55,7 +51,6 @@ impl lai::Host for LaiHost { fn sleep(&self, ms: u64) { scheduler::get_scheduler() - .inner .sleep(Some(ms as usize / 1000)) .expect("lai: unexpected signal during sleep") } @@ -121,6 +116,12 @@ impl aml::AmlSubsystem for LaiSubsystem { fn enable_acpi(&self, mode: u32) { lai::enable_acpi(mode); } + + fn pci_route_pin(&self, seg: u16, bus: u8, slot: u8, function: u8, pin: u8) -> u8 { + lai::pci_route_pin(seg, bus, slot, function, pin) + .expect("lai: failed to route pin") + .base as u8 + } } pub fn init_lai() { @@ -134,4 +135,4 @@ pub fn init_lai() { aml::init(subsystem); } -crate::module_init!(init_lai); +crate::module_init!(init_lai, ModuleType::Block); diff --git a/src/aero_kernel/src/drivers/mod.rs b/src/aero_kernel/src/drivers/mod.rs index 5f0b2260ab7..edb23988a46 100644 --- a/src/aero_kernel/src/drivers/mod.rs +++ b/src/aero_kernel/src/drivers/mod.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #[cfg(target_arch = "x86_64")] pub mod block; @@ -28,15 +26,22 @@ pub mod keyboard; #[cfg(target_arch = "x86_64")] pub mod lai; // FIXME: aarch64 port +pub mod e1000; +// #[cfg(feature = "gdbstub")] +pub mod gdbstub; +pub mod mouse; #[cfg(target_arch = "x86_64")] pub mod pci; +pub mod pty; pub mod tty; -cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { +cfg_match! { + target_arch = "x86_64" => { pub mod uart_16550; pub use self::uart_16550 as uart; - } else if #[cfg(target_arch = "aarch64")] { + } + + target_arch = "aarch64" => { pub mod uart_pl011; pub use self::uart_pl011 as uart; } diff --git a/src/aero_kernel/src/drivers/mouse.rs b/src/aero_kernel/src/drivers/mouse.rs new file mode 100644 index 00000000000..591cbeabbdb --- /dev/null +++ b/src/aero_kernel/src/drivers/mouse.rs @@ -0,0 +1,198 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::OpenFlags; +use alloc::sync::Arc; +use alloc::vec::Vec; + +use crate::arch::interrupts::InterruptStack; +use crate::arch::{apic, interrupts, io}; +use crate::fs::devfs::Device; +use crate::fs::inode::{INodeInterface, PollFlags, PollTable}; +use crate::fs::{self, devfs}; +use crate::utils::sync::{Mutex, WaitQueue}; + +bitflags::bitflags! { + /// Represents the flags currently set for the mouse. + #[derive(Default, Debug, Copy, Clone)] + pub struct MouseFlags: u8 { + const LEFT_BUTTON = 0b0000_0001; + const RIGHT_BUTTON = 0b0000_0010; + const MIDDLE_BUTTON = 0b0000_0100; + const ALWAYS_ONE = 0b0000_1000; + const X_SIGN = 0b0001_0000; + const Y_SIGN = 0b0010_0000; + const X_OVERFLOW = 0b0100_0000; + const Y_OVERFLOW = 0b1000_0000; + } +} + +const DATA_PORT: u16 = 0x60; +const CMD_PORT: u16 = 0x64; + +lazy_static::lazy_static! { + static ref MOUSE: Arc = Arc::new(Mouse::new()); +} + +static PACKETS: Mutex> = Mutex::new(Vec::new()); + +#[derive(Default, Debug, Copy, Clone)] +#[repr(C)] +struct Packet { + x: i16, + y: i16, + + flags: MouseFlags, +} + +struct Mouse { + packet: Mutex<(Packet, usize)>, + wq: WaitQueue, + marker: usize, +} + +impl Mouse { + fn new() -> Mouse { + Self { + packet: Mutex::new((Packet::default(), 0)), + wq: WaitQueue::new(), + marker: devfs::alloc_device_marker(), + } + } + + fn process_packet(&self, packet: u8) { + let sign_extend = |v: u8| ((v as u16) | 0xFF00) as i16; + let mut inner = self.packet.lock_irq(); + + match inner.1 { + 0 => { + // The first packet contains the mouse flags. + let flags = MouseFlags::from_bits_truncate(packet); + let this = &mut inner.0; + + this.flags = flags; + } + + 1 => { + let this = &mut inner.0; + + // The second byte contains the "delta X". + if !this.flags.contains(MouseFlags::X_OVERFLOW) { + if this.flags.contains(MouseFlags::X_SIGN) { + this.x = sign_extend(packet); + } else { + this.x = packet as i16; + } + } + } + + 2 => { + let this = &mut inner.0; + + // The third packet contains the "delta Y". + if !this.flags.contains(MouseFlags::Y_OVERFLOW) { + if this.flags.contains(MouseFlags::Y_SIGN) { + this.y = sign_extend(packet); + } else { + this.y = packet as i16; + } + + PACKETS.lock_irq().push(*this); + self.wq.notify_all(); + } + } + + _ => unreachable!(), + } + + inner.1 = (inner.1 + 1) % 3; + } +} + +impl Device for Mouse { + fn device_marker(&self) -> usize { + self.marker + } + + fn device_name(&self) -> String { + String::from("mouse0") + } + + fn inode(&self) -> Arc { + MOUSE.clone() + } +} + +impl INodeInterface for Mouse { + fn read_at(&self, _flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> fs::Result { + let size = core::mem::size_of::(); + + if buffer.len() < size { + return Err(fs::FileSystemError::NotSupported); + } + + let packet = PACKETS + .lock_irq() + .pop() + .ok_or(fs::FileSystemError::WouldBlock)?; + + unsafe { + *(buffer.as_mut_ptr().cast::()) = packet; + } + + Ok(size) + } + + fn poll(&self, table: Option<&mut PollTable>) -> fs::Result { + if let Some(e) = table { + e.insert(&MOUSE.wq) + } + + if !PACKETS.lock_irq().is_empty() { + Ok(PollFlags::IN) + } else { + Ok(PollFlags::empty()) + } + } +} + +fn irq_handler(_stack: &mut InterruptStack) { + let data = unsafe { io::inb(0x60) }; + MOUSE.process_packet(data); +} + +pub fn ps2_mouse_init() { + let irq_vector = interrupts::allocate_vector(); + interrupts::register_handler(irq_vector, irq_handler); + + unsafe { + io::outb(CMD_PORT, 0xd4); + io::outb(DATA_PORT, 0xF6); + while io::inb(DATA_PORT) != 0xfa {} + io::outb(CMD_PORT, 0xd4); + io::outb(DATA_PORT, 0xf4); + while io::inb(DATA_PORT) != 0xfa {} + io::outb(CMD_PORT, 0xd4); + io::outb(DATA_PORT, 0xE7); + while io::inb(DATA_PORT) != 0xfa {} + } + + apic::io_apic_setup_legacy_irq(12, irq_vector, 1); + + devfs::install_device(MOUSE.clone()).unwrap(); + log::trace!("ps2: initialized mouse"); +} diff --git a/src/aero_kernel/src/drivers/pci.rs b/src/aero_kernel/src/drivers/pci.rs index 7038a3b7210..91851f76d29 100644 --- a/src/aero_kernel/src/drivers/pci.rs +++ b/src/aero_kernel/src/drivers/pci.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::alloc::Global; use alloc::sync::Arc; @@ -25,7 +23,7 @@ use crate::utils::bitmap::Bitmap; use crate::utils::sync::Mutex; use crate::acpi::mcfg; -use crate::mem::paging::OffsetPageTable; +use crate::mem::paging::{OffsetPageTable, PhysAddr}; use crate::utils::VolatileCell; use crate::arch::{apic, io}; @@ -47,6 +45,13 @@ bitflags::bitflags! { } } +#[repr(u32)] +pub enum DeliveryMode { + /// Deliver the signal to all the agents listed in the destination. The Trigger Mode for + /// fixed delivery mode can be edge or level. + Fixed = 0b000, +} + #[repr(C)] struct Message { addr_lower: VolatileCell, @@ -62,13 +67,18 @@ impl Message { fn set_masked(&self, masked: bool) { self.mask.set(*self.mask.get().set_bit(0, masked)); + self.mask.set(*self.mask.get().set_bit(30, masked)); } - fn set(&mut self, vector: u8) { + fn set(&mut self, vector: u8, delivery_mode: DeliveryMode) { assert!(self.is_masked(), "msix: message is unmasked"); let mut data = 0; data.set_bits(0..8, vector as u32); + data.set_bits(8..11, delivery_mode as u32); + data.set_bit(14, false); + data.set_bit(15, false); + data.set_bits(16..32, 0); let mut addr = 0; addr.set_bits(12..20, apic::get_bsp_id() as u32); @@ -106,16 +116,18 @@ impl<'a> Msix<'a> { .get_bar(bar_index) .expect("msix: table bar not present"); + map_bar(&bar); + let bar_address = match bar { - Bar::Memory64 { address, .. } => address, - Bar::Memory32 { address, .. } => address as u64, + Bar::Memory64 { address, .. } => PhysAddr::new(address), + Bar::Memory32 { address, .. } => PhysAddr::new(address as u64), _ => unreachable!(), }; // SAFETY: We have exclusive access to the BAR and the slice is in bounds. let messages = unsafe { core::slice::from_raw_parts_mut( - (bar_address + bar_offset as u64) as *mut Message, + (bar_address.as_hhdm_virt() + bar_offset as u64).as_mut_ptr::(), table_length as usize, ) }; @@ -124,6 +136,7 @@ impl<'a> Msix<'a> { message_control.set_bit(15, true); // enable MSI-X message_control.set_bit(14, false); // function mask + header.disable_legacy_irq(); header.write::(offset + 2, message_control as u32); } @@ -142,7 +155,7 @@ impl<'a> Msix<'a> { self.table.set(msix_vector, true); let message = &mut self.messages[msix_vector]; - message.set(vector); + message.set(vector, DeliveryMode::Fixed); message.set_masked(false); msix_vector @@ -171,7 +184,7 @@ impl<'a> CapabilityIter<'a> { } } -impl<'a> Iterator for CapabilityIter<'a> { +impl Iterator for CapabilityIter<'_> { type Item = (u32, Capability); fn next(&mut self) -> Option { @@ -221,15 +234,11 @@ pub enum Bar { pub enum DeviceType { Unknown, - /* - * Base Class 0x00 - Devices that predate Class Codes - */ + // Base Class 0x00 - Devices that predate Class Codes LegacyVgaCompatible, LegacyNotVgaCompatible, - /* - * Base Class 0x01 - Mass Storage Controllers - */ + // Base Class 0x01 - Mass Storage Controllers ScsiBusController, IdeController, FloppyController, @@ -241,9 +250,7 @@ pub enum DeviceType { NvmeController, OtherMassStorageController, - /* - * Base Class 0x02 - Network Controllers - */ + // Base Class 0x02 - Network Controllers EthernetController, TokenRingController, FddiController, @@ -252,32 +259,24 @@ pub enum DeviceType { PicmgController, OtherNetworkController, - /* - * Base Class 0x03 - Display Controllers - */ + // Base Class 0x03 - Display Controllers VgaCompatibleController, XgaController, ThreeDController, OtherDisplayController, - /* - * Base Class 0x04 - Multimedia Devices - */ + // Base Class 0x04 - Multimedia Devices VideoDevice, AudioDevice, TelephonyDevice, OtherMultimediaDevice, - /* - * Base Class 0x05 - Memory Controllers - */ + // Base Class 0x05 - Memory Controllers RamController, FlashController, OtherMemoryController, - /* - * Base Class 0x06 - Bridge Devices - */ + // Base Class 0x06 - Bridge Devices HostBridge, IsaBridge, EisaBridge, @@ -291,9 +290,7 @@ pub enum DeviceType { InfinibandPciHostBridge, OtherBridgeDevice, - /* - * Base Class 0x07 - Simple Communications Controllers - */ + // Base Class 0x07 - Simple Communications Controllers SerialController, ParallelPort, MultiportSerialController, @@ -302,9 +299,7 @@ pub enum DeviceType { SmartCard, OtherCommunicationsDevice, - /* - * Base Class 0x08 - Generic System Peripherals - */ + // Base Class 0x08 - Generic System Peripherals InterruptController, DmaController, SystemTimer, @@ -313,9 +308,7 @@ pub enum DeviceType { SdHostController, OtherSystemPeripheral, - /* - * Base Class 0x09 - Input Devices - */ + // Base Class 0x09 - Input Devices KeyboardController, Digitizer, MouseController, @@ -323,15 +316,11 @@ pub enum DeviceType { GameportController, OtherInputController, - /* - * Base Class 0x0a - Docking Stations - */ + // Base Class 0x0a - Docking Stations GenericDockingStation, OtherDockingStation, - /* - * Base Class 0x0b - Processors - */ + // Base Class 0x0b - Processors Processor386, Processor486, ProcessorPentium, @@ -340,9 +329,7 @@ pub enum DeviceType { ProcessorMips, CoProcessor, - /* - * Base Class 0x0c - Serial Bus Controllers - */ + // Base Class 0x0c - Serial Bus Controllers FirewireController, AccessBusController, SsaBusController, @@ -354,9 +341,7 @@ pub enum DeviceType { SercosController, CanBusController, - /* - * Base Class 0x0d - Wireless Controllers - */ + // Base Class 0x0d - Wireless Controllers IrdaController, ConsumerIrController, RfController, @@ -366,29 +351,21 @@ pub enum DeviceType { Ethernet24GHzController, OtherWirelessController, - /* - * Base Class 0x0e - Intelligent IO Controllers - */ + // Base Class 0x0e - Intelligent IO Controllers IntelligentIoController, - /* - * Base Class 0x0f - Satellite Communications Controllers - */ + // Base Class 0x0f - Satellite Communications Controllers TvSatelliteCommunicationsController, AudioSatelliteCommunicationsController, VoiceSatelliteCommunicationsController, DataSatelliteCommunicationsController, - /* - * Base Class 0x10 - Encryption and Decryption Controllers - */ + // Base Class 0x10 - Encryption and Decryption Controllers NetworkCryptionController, EntertainmentCryptionController, OtherCryptionController, - /* - * Base Class 0x11 - Data Acquisition and Signal Processing Controllers - */ + // Base Class 0x11 - Data Acquisition and Signal Processing Controllers DpioModule, PerformanceCounter, CommunicationsSynchronizationController, @@ -527,8 +504,8 @@ impl DeviceType { #[derive(Debug, PartialEq)] pub enum Vendor { Intel, - AMD, - NVIDIA, + Amd, + Nvidia, Qemu, Unknown(u32), } @@ -537,8 +514,8 @@ impl Vendor { pub fn new(id: u32) -> Self { match id { 0x8086 => Self::Intel, - 0x1022 => Self::AMD, - 0x10DE => Self::NVIDIA, + 0x1022 => Self::Amd, + 0x10DE => Self::Nvidia, 0x1234 => Self::Qemu, _ => Self::Unknown(id), } @@ -586,26 +563,42 @@ impl PciHeader { io::outl(PCI_CONFIG_ADDRESS_PORT, address); + let offset = (offset & 0b11) * 8; + let val = io::inl(PCI_CONFIG_DATA_PORT); + match core::mem::size_of::() { - 1 => io::inb(PCI_CONFIG_DATA_PORT) as u32, // u8 - 2 => io::inw(PCI_CONFIG_DATA_PORT) as u32, // u16 - 4 => io::inl(PCI_CONFIG_DATA_PORT), // u32 + 1 => (val >> offset) as u8 as u32, // u8 + 2 => (val >> offset) as u16 as u32, // u16 + 4 => val, // u32 width => unreachable!("unknown PCI read width: `{}`", width), } } unsafe fn write(&self, offset: u32, value: u32) { + let current = self.read::(offset); + let bus = self.bus() as u32; let device = self.device() as u32; let func = self.function() as u32; + let address = (bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x80000000; + let noffset = (offset & 0b11) * 8; io::outl(PCI_CONFIG_ADDRESS_PORT, address); - match core::mem::size_of::() { - 1 => io::outb(PCI_CONFIG_DATA_PORT, value as u8), // u8 - 2 => io::outw(PCI_CONFIG_DATA_PORT, value as u16), // u16 - 4 => io::outl(PCI_CONFIG_DATA_PORT, value), // u32 + 1 => { + let mask = !(0xffu32 << offset); + let value = (current & mask) | ((value & 0xff) << offset); + io::outl(PCI_CONFIG_DATA_PORT, value) + } // u8 + + 2 => { + let mask = !(0xffffu32 << noffset); + let value = (current & mask) | ((value & 0xffff) << noffset); + io::outl(PCI_CONFIG_DATA_PORT, value) + } // u16 + + 4 => io::outl(PCI_CONFIG_DATA_PORT, value), // u32 width => unreachable!("unknown PCI write width: `{}`", width), } } @@ -633,6 +626,15 @@ impl PciHeader { unsafe { self.write::(0x04, command | (1 << 2)) } } + pub fn disable_legacy_irq(&self) { + // Set the Interrupt Disable bit, which is bit 10 of the Command register + // (at Configuration Space offset 0x4) to disable legacy interrupts. + let mut command = unsafe { self.read::(0x04) }; + command.set_bit(10, true); + + unsafe { self.write::(0x04, command) } + } + /// Returns the value stored in the PCI vendor ID register which is used to identify /// the manufacturer of the PCI device. pub fn get_vendor(&self) -> Vendor { @@ -649,7 +651,7 @@ impl PciHeader { unsafe { self.read::(0x0c) }.get_bit(23) } - /// Returnes the value stored in the PCI header type register which is used to + /// Returns the value stored in the PCI header type register which is used to /// indicate layout for bytes,of the device’s configuration space. pub fn get_header_type(&self) -> u8 { unsafe { self.read::(0x0E) as u8 & 0b01111111 } @@ -677,7 +679,9 @@ impl PciHeader { // bit 0:true - the BAR is in memory // bit 0:false - the BAR is in I/O - if !bar.get_bit(0) { + if bar.get_bit(0) { + Some(Bar::IO(bar.get_bits(2..32))) + } else { let prefetchable = bar.get_bit(3); let address = bar.get_bits(4..32) << 4; @@ -725,11 +729,13 @@ impl PciHeader { _ => None, } - } else { - Some(Bar::IO(bar.get_bits(2..32))) } } + pub fn interrupt_pin(&self) -> u8 { + unsafe { self.read::(0x3d) as u8 } + } + // NOTE: The Base Address registers are optional registers used to map internal // (device-specific) registers into Memory or I/O Spaces. Refer to the PCI Local Bus // Specification for a detailed discussion of base address registers. @@ -784,23 +790,60 @@ impl PciTable { } } +pub fn map_bar(bar: &Bar) { + use crate::mem::paging::{Mapper, Page, PageTableFlags, PhysFrame, Size4KiB, UnmapError}; + + use crate::mem::AddressSpace; + + let mut address_space = AddressSpace::this(); + let mut offset_table = address_space.offset_page_table(); + + let (addr, size) = match bar { + Bar::Memory64 { address, size, .. } => (PhysAddr::new(*address), *size), + _ => unreachable!(), + }; + + for frame in PhysFrame::range( + PhysFrame::::from_start_address(addr).unwrap(), + PhysFrame::containing_address(addr + size), + ) { + let virt = frame.start_address().as_hhdm_virt(); + let page = Page::containing_address(virt); + + // Map will fail if the bar was partially mapped. + match offset_table.unmap(page) { + Ok((_, m)) => m.ignore(), + Err(UnmapError::PageNotMapped) => {} + Err(e) => unreachable!("{:?}", e), + } + + unsafe { + offset_table.map_to( + page, + frame, + PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE, + ) + } + .unwrap() + .flush(); + } +} + pub fn register_device_driver(handle: Arc) { PCI_TABLE.lock().inner.push(PciDevice { handle }) } /// Lookup and initialize all PCI devices. pub fn init(offset_table: &mut OffsetPageTable) { - // Check if the MCFG table is avaliable. - if mcfg::is_avaliable() { + // Check if the MCFG table is available. + if mcfg::is_available() { let mcfg_table = mcfg::get_mcfg_table(); let _entry_count = mcfg_table.entry_count(); } - /* - * Use the brute force method to go through each possible bus, - * device, function ID and check if we have a driver for it. If a driver - * for the PCI device is found then initialize it. - */ + // Use the brute force method to go through each possible bus, + // device, function ID and check if we have a driver for it. If a driver + // for the PCI device is found then initialize it. for bus in 0..255 { for device in 0..32 { let function_count = if PciHeader::new(bus, device, 0x00).has_multiple_functions() { diff --git a/src/aero_kernel/src/drivers/pty.rs b/src/aero_kernel/src/drivers/pty.rs new file mode 100644 index 00000000000..973740f2d49 --- /dev/null +++ b/src/aero_kernel/src/drivers/pty.rs @@ -0,0 +1,467 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::sync::atomic::{AtomicU32, Ordering}; + +use aero_syscall::{self as libc, OpenFlags, Termios, WinSize}; + +use alloc::collections::BTreeMap; +use alloc::string::ToString; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use spin::{Once, RwLock}; + +use uapi::pty::TIOCGPTN; + +use crate::arch::user_copy::UserRef; +use crate::fs::cache::*; +use crate::fs::devfs::DEV_FILESYSTEM; +use crate::fs::inode::{DirEntry, FileType, INodeInterface, PollFlags}; +use crate::fs::{self, cache, devfs, FileSystem, FileSystemError, Path, MOUNT_MANAGER}; + +use crate::mem::paging::VirtAddr; +use crate::userland::scheduler; +use crate::userland::scheduler::ExitStatus; +use crate::userland::task::Task; +use crate::userland::terminal::{LineControl, LineDiscipline, TerminalDevice}; +use crate::utils::sync::{Mutex, WaitQueue}; + +lazy_static::lazy_static! { + static ref PTMX: Arc = Arc::new(Ptmx::new()); +} + +static PTS_FS: Once> = Once::new(); +static PTY_ID: AtomicU32 = AtomicU32::new(0); + +#[derive(Debug, Ioctl)] +pub enum TermiosCmd { + /// Get window size. + #[command(libc::TIOCGWINSZ)] + GetWinSize(UserRef), + + /// Set window size. + #[command(libc::TIOCSWINSZ)] + SetWinSize(UserRef), + + /// Get the current serial port settings. + /// + /// Equivalent to `tcgetattr(fd, argp)`. + #[command(libc::TCGETS)] + TcGets(UserRef), + + /// Allow the output buffer to drain, discard pending input, and set the current serial + /// port settings. + /// + /// Equivalent to `tcsetattr(fd, TCSAFLUSH, argp)`. + #[command(libc::TCSETSF)] + TcSetsf(UserRef), + + /// Allow the output buffer to drain, and set the current serial port settings. + /// + /// Equivalent to `tcsetattr(fd, TCSADRAIN, argp)`. + #[command(libc::TCSETSW)] + TcSetsw(UserRef), + + /// Make the given terminal the controlling terminal of the calling process. The calling + /// process must be a session leader and not have a controlling terminal already. For this + /// case, arg should be specified as zero. + /// + /// If this terminal is already the controlling terminal of a different session group, then the + /// ioctl fails with EPERM, unless the caller has the CAP_SYS_ADMIN capability and arg equals + /// 1, in which case the terminal is stolen, and all processes that had it as controlling + /// terminal lose it. + // FIXME: argument usize + #[command(libc::TIOCSCTTY)] + SetCtrlTerm, + + /// Get the process group ID of the foreground process group on this terminal. + /// + /// When successful, equivalent to `*argp = tcgetpgrp(fd)`. + // FIXME: argument usize + #[command(libc::TIOCGPGRP)] + GetProcGroupId, +} + +struct Master { + id: u32, + wq: WaitQueue, + window_size: Mutex, + buffer: Mutex>, + discipline: LineDiscipline, +} + +impl Master { + pub fn new() -> Self { + Self { + id: PTY_ID.fetch_add(1, Ordering::SeqCst), + wq: WaitQueue::new(), + window_size: Mutex::new(WinSize::default()), + buffer: Mutex::new(Vec::new()), + discipline: LineDiscipline::new(), + } + } + + #[inline] + fn set_window_size(&self, size: WinSize) { + *self.window_size.lock_irq() = size; + } + + #[inline] + fn get_window_size(&self) -> WinSize { + *self.window_size.lock_irq() + } +} + +impl INodeInterface for Master { + fn read_at(&self, _flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> fs::Result { + let mut pty_buffer = self.buffer.lock_irq(); + + if pty_buffer.is_empty() { + return Err(FileSystemError::WouldBlock); + } + + let size = core::cmp::min(pty_buffer.len(), buffer.len()); + buffer[..size].copy_from_slice(&pty_buffer.drain(..size).collect::>()); + Ok(size) + } + + fn write_at(&self, _offset: usize, buffer: &[u8]) -> fs::Result { + self.discipline.write(buffer, |ctrl| match ctrl { + LineControl::Echo(c) => self.buffer.lock_irq().push(c), + }); + self.wq.notify_all(); + Ok(buffer.len()) + } + + fn poll(&self, table: Option<&mut fs::inode::PollTable>) -> fs::Result { + if let Some(e) = table { + e.insert(&self.wq) + } + let mut flags = fs::inode::PollFlags::OUT; + + if !self.buffer.lock_irq().is_empty() { + flags |= fs::inode::PollFlags::IN; + } + + Ok(flags) + } + + fn ioctl(&self, command: usize, arg: usize) -> fs::Result { + match command { + TIOCGPTN => { + let id = VirtAddr::new(arg as u64).read_mut::()?; + *id = self.id; + } + + aero_syscall::TIOCSWINSZ => { + let winsize = VirtAddr::new(arg as u64).read_mut::()?; + *self.window_size.lock_irq() = *winsize; + } + + _ => { + panic!("ptmx: unknown ioctl (command={command:#x})") + } + } + + Ok(0) + } +} + +impl TerminalDevice for Slave { + fn attach(&self, task: Arc) { + assert!(task.is_session_leader()); + self.master.discipline.set_foreground(&task); + } + + fn detach(&self, task: Arc) { + use aero_syscall::signal::SIGINT; + use aero_syscall::VINTR; + + if !self.master.discipline.termios.lock().is_cooked() { + return; + } + + if let ExitStatus::Signal(signo) = task.exit_status() { + let mut buffer = self.master.buffer.lock_irq(); + let termios = self.master.discipline.termios.lock(); + + // converts `X` into `^X` and pushes the result into the master PTY buffer. + let mut ctrl = |c| { + buffer.extend_from_slice(&[b'^', c + 0x40]); + }; + + if *signo == SIGINT { + ctrl(termios.c_cc[VINTR]) + } + } + } +} + +struct Slave { + sref: Weak, + master: Arc, +} + +impl Slave { + pub fn new(master: Arc) -> Arc { + Arc::new_cyclic(|sref| Self { + sref: sref.clone(), + master, + }) + } + + fn sref(&self) -> Arc { + self.sref.upgrade().unwrap() + } +} + +impl INodeInterface for Slave { + fn metadata(&self) -> fs::Result { + Ok(fs::inode::Metadata::with_file_type(FileType::Device)) + } + + fn stat(&self) -> fs::Result { + Ok(aero_syscall::Stat::default()) + } + + fn ioctl(&self, command: usize, arg: usize) -> fs::Result { + match TermiosCmd::from_command_arg(command, arg) { + TermiosCmd::GetWinSize(mut size) => *size = self.master.get_window_size(), + TermiosCmd::SetWinSize(size) => self.master.set_window_size(*size), + TermiosCmd::TcGets(mut termios) => *termios = self.master.discipline.termios(), + TermiosCmd::TcSetsf(termios) => self.master.discipline.set_termios(termios.clone()), + TermiosCmd::TcSetsw(termios) => { + // TODO: Allow the output buffer to drain and then set the current serial port + // settings. + self.master.discipline.set_termios(termios.clone()) + } + + TermiosCmd::SetCtrlTerm => { + let current_task = scheduler::get_scheduler().current_task(); + assert!(current_task.is_session_leader()); + + current_task.attach(self.sref()); + } + + // FIXME: the following ioctls are not implemented. + TermiosCmd::GetProcGroupId => return Err(FileSystemError::NotSupported), + } + + Ok(0) + } + + fn poll(&self, table: Option<&mut fs::inode::PollTable>) -> fs::Result { + if let Some(table) = table { + table.insert(&self.master.wq); + table.insert(self.master.discipline.wait_queue()); + } + + let mut flags = PollFlags::OUT; + + if !self.master.discipline.is_empty() { + flags |= PollFlags::IN; + } + + Ok(flags) + } + + fn read_at(&self, _flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> fs::Result { + Ok(self.master.discipline.read(buffer)?) + } + + fn write_at(&self, _offset: usize, buffer: &[u8]) -> fs::Result { + if self + .master + .discipline + .termios() + .c_oflag + .contains(aero_syscall::TermiosOFlag::ONLCR) + { + let mut master = self.master.buffer.lock_irq(); + + for b in buffer.iter() { + if *b == b'\n' { + // ONLCR: Convert NL to CR + NL + master.extend_from_slice(b"\r\n"); + continue; + } + + master.push(*b); + } + } else { + let mut pty_buffer = self.master.buffer.lock_irq(); + pty_buffer.extend_from_slice(buffer); + } + + self.master.wq.notify_all(); + Ok(buffer.len()) + } +} + +struct Ptmx { + device_id: usize, +} + +impl Ptmx { + fn new() -> Self { + Self { + device_id: devfs::alloc_device_marker(), + } + } +} + +impl devfs::Device for Ptmx { + fn device_marker(&self) -> usize { + self.device_id + } + + fn device_name(&self) -> String { + String::from("ptmx") + } + + fn inode(&self) -> Arc { + PTMX.clone() + } +} + +impl INodeInterface for Ptmx { + fn open(&self, _handle: Arc) -> fs::Result> { + let master = Arc::new(Master::new()); + let slave = Slave::new(master.clone()); + let inode = DirEntry::from_inode(master, String::from("")); + + PTS_FS.get().unwrap().insert_slave(slave); + Ok(Some(inode)) + } +} + +#[derive(Default)] +struct PtsINode { + inode: Once, + fs: Once>, + slaves: RwLock>, +} + +impl INodeInterface for PtsINode { + fn metadata(&self) -> fs::Result { + Ok(fs::inode::Metadata { + id: 0, + file_type: FileType::Directory, + children_len: self.slaves.read().len(), + size: 0, + }) + } + + fn stat(&self) -> fs::Result { + Ok(aero_syscall::Stat::default()) + } + + fn dirent(&self, parent: DirCacheItem, index: usize) -> fs::Result> { + Ok(match index { + 0x00 => Some(DirEntry::new( + parent, + self.inode.get().unwrap().clone(), + String::from("."), + )), + + 0x01 => Some(DirEntry::new( + parent, + self.inode.get().unwrap().clone(), + String::from(".."), + )), + + _ => { + let a = self + .slaves + .read() + .iter() + .nth(index - 2) + .map(|(id, inode)| DirEntry::new(parent, inode.clone(), id.to_string())); + log::debug!("{}", a.is_some()); + a + } + }) + } + + fn lookup(&self, dir: DirCacheItem, name: &str) -> fs::Result { + let id = name.parse::().unwrap(); + let slaves = self.slaves.read(); + + let (_, inode) = slaves + .iter() + .find(|(&e, _)| e == id) + .ok_or(FileSystemError::EntryNotFound)?; + + Ok(DirEntry::new(dir, inode.clone(), String::from(name))) + } + + fn weak_filesystem(&self) -> Option> { + Some(self.fs.get()?.clone()) + } +} + +struct PtsFs { + root_dir: DirCacheItem, +} + +impl PtsFs { + fn new() -> Arc { + let icache = cache::icache(); + let root_inode = icache.make_item_no_cache(CachedINode::new(Arc::new(PtsINode::default()))); + + let root_dir = DirEntry::new_root(root_inode.clone(), String::from("/")); + let pts_root = root_dir.inode().downcast_arc::().unwrap(); + + let this = Arc::new(Self { root_dir }); + + // Initialize the PTS root inode. + pts_root.fs.call_once(|| Arc::downgrade(&this)); + pts_root.inode.call_once(|| root_inode.clone()); + + this + } + + fn insert_slave(&self, slave: Arc) { + let icache = cache::icache(); + + let pts_root = self.root_dir.inode().downcast_arc::().unwrap(); + pts_root.slaves.write().insert( + slave.master.id, + icache.make_item_no_cache(CachedINode::new(slave)), + ); + } +} + +impl fs::FileSystem for PtsFs { + fn root_dir(&self) -> DirCacheItem { + self.root_dir.clone() + } +} + +fn pty_init() { + devfs::install_device(PTMX.clone()).unwrap(); + + let fs = PTS_FS.call_once(PtsFs::new); + + let root = DEV_FILESYSTEM.root_dir().inode(); + root.mkdir("pts").unwrap(); + + let pts_dir = fs::lookup_path(Path::new("/dev/pts")).unwrap(); + MOUNT_MANAGER.mount(pts_dir, fs.clone()).unwrap(); +} + +crate::module_init!(pty_init, ModuleType::Other); diff --git a/src/aero_kernel/src/drivers/tty/ctty.rs b/src/aero_kernel/src/drivers/tty/ctty.rs new file mode 100644 index 00000000000..dfe8345909d --- /dev/null +++ b/src/aero_kernel/src/drivers/tty/ctty.rs @@ -0,0 +1,118 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +//! `/dev/tty`: Controlling terminal of the current process. + +use aero_syscall::{OpenFlags, TIOCNOTTY}; +use alloc::sync::{Arc, Weak}; + +use crate::fs::devfs::Device; +use crate::fs::inode::{FileType, INodeInterface, Metadata, PollFlags, PollTable}; +use crate::fs::{self, devfs, FileSystemError}; +use crate::userland::scheduler; + +struct Ctty { + device_id: usize, + sref: Weak, +} + +impl Ctty { + fn new() -> Arc { + Arc::new_cyclic(|sref| Self { + device_id: devfs::alloc_device_marker(), + sref: sref.clone(), + }) + } + + /// Returns the controlling terminal device of the current process. + fn controlling_terminal() -> fs::Result> { + let current_task = scheduler::get_scheduler().current_task(); + let terminal_device = current_task.controlling_terminal(); + + terminal_device + .map(|device| device as Arc) + .ok_or(FileSystemError::NoTty) + } + + #[inline] + fn sref(&self) -> Arc { + self.sref.upgrade().unwrap() + } +} + +impl INodeInterface for Ctty { + fn metadata(&self) -> fs::Result { + Ok(Metadata { + id: 0, + file_type: FileType::Device, + size: 0, + children_len: 0, + }) + } + + fn read_at(&self, flags: OpenFlags, offset: usize, buffer: &mut [u8]) -> fs::Result { + Self::controlling_terminal()?.read_at(flags, offset, buffer) + } + + fn write_at(&self, offset: usize, buffer: &[u8]) -> fs::Result { + Self::controlling_terminal()?.write_at(offset, buffer) + } + + fn poll(&self, table: Option<&mut PollTable>) -> fs::Result { + Self::controlling_terminal()?.poll(table) + } + + /// ### Supported `ioctl(2)` requests + /// + /// In addition to the `ioctl(2)` requests supported by the device that CTTY refers to, the + /// `ioctl(2)` request `TIOCNOTTY` is supported. + fn ioctl(&self, command: usize, arg: usize) -> fs::Result { + match command { + TIOCNOTTY => { + let current_task = scheduler::get_scheduler().current_task(); + current_task.detach(); + + Ok(0) + } + + _ => Self::controlling_terminal()?.ioctl(command, arg), + } + } +} + +impl Device for Ctty { + #[inline] + fn device_marker(&self) -> usize { + self.device_id + } + + #[inline] + fn device_name(&self) -> String { + String::from("tty") + } + + #[inline] + fn inode(&self) -> Arc { + self.sref() + } +} + +/// Registers the `/dev/ctty` character device. +pub fn init() -> fs::Result<()> { + devfs::install_device(Ctty::new())?; + Ok(()) +} diff --git a/src/aero_kernel/src/drivers/tty/mod.rs b/src/aero_kernel/src/drivers/tty/mod.rs new file mode 100644 index 00000000000..ed6b630ad4d --- /dev/null +++ b/src/aero_kernel/src/drivers/tty/mod.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +mod ctty; +mod vtty; + +fn init() { + ctty::init().unwrap(); + vtty::init().unwrap(); +} + +crate::module_init!(init, ModuleType::Other); diff --git a/src/aero_kernel/src/drivers/tty.rs b/src/aero_kernel/src/drivers/tty/vtty.rs similarity index 52% rename from src/aero_kernel/src/drivers/tty.rs rename to src/aero_kernel/src/drivers/tty/vtty.rs index 159fca09fbc..f86eb80de83 100644 --- a/src/aero_kernel/src/drivers/tty.rs +++ b/src/aero_kernel/src/drivers/tty/vtty.rs @@ -1,49 +1,54 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +//! `/dev/vtty[0-9]`: virtual terminals + +use core::sync::atomic::{AtomicUsize, Ordering}; + +use aero_syscall::OpenFlags; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; -use crate::fs; -use crate::fs::devfs; use crate::fs::inode::{self, PollFlags, PollTable}; -use crate::rendy; +use crate::fs::{devfs, FileSystemError}; +use crate::{fs, rendy}; use crate::fs::inode::INodeInterface; use crate::mem::paging::VirtAddr; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::userland::scheduler; +use crate::userland::task::Task; +use crate::userland::terminal::TerminalDevice; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueFlags}; #[cfg(target_arch = "x86_64")] -use super::keyboard::KeyCode; +use crate::drivers::keyboard::KeyCode; #[cfg(target_arch = "x86_64")] -use super::keyboard::KeyboardListener; +use crate::drivers::keyboard::KeyboardListener; lazy_static::lazy_static! { static ref TTY: Arc = Tty::new(); static ref TERMIOS: Mutex = Mutex::new(aero_syscall::Termios { - c_iflag: 0, + c_iflag: aero_syscall::TermiosIFlag::empty(), c_oflag: aero_syscall::TermiosOFlag::empty(), c_cflag: aero_syscall::TermiosCFlag::empty(), c_lflag: aero_syscall::TermiosLFlag::ECHO | aero_syscall::TermiosLFlag::ICANON, c_line: 0, - c_cc: [0; 11], + c_cc: [0; 32], c_ispeed: 0, c_ospeed: 0, }); @@ -172,7 +177,7 @@ impl StdinBuffer { } fn is_complete(&self) -> bool { - self.back_buffer.len() > 0 || self.front_buffer.len() > 0 + !self.back_buffer.is_empty() || !self.front_buffer.is_empty() } fn advance_cursor(&mut self) { @@ -188,8 +193,6 @@ struct TtyState { lalt: bool, altgr: bool, caps: bool, - - parser: vte::Parser, } struct Tty { @@ -198,7 +201,9 @@ struct Tty { sref: Weak, stdin: Mutex, - block_queue: BlockQueue, + block_queue: WaitQueue, + + connected: AtomicUsize, } impl Tty { @@ -213,22 +218,41 @@ impl Tty { lalt: false, altgr: false, caps: false, - - parser: vte::Parser::new(), }), - block_queue: BlockQueue::new(), + block_queue: WaitQueue::new(), stdin: Mutex::new(StdinBuffer::new()), + connected: AtomicUsize::new(0), sref: sref.clone(), }) } } impl INodeInterface for Tty { - fn read_at(&self, _offset: usize, buffer: &mut [u8]) -> fs::Result { - self.block_queue - .block_on(&self.stdin, |future| future.is_complete())?; + fn open( + &self, + _handle: Arc, + ) -> fs::Result> { + let connected = self.connected.fetch_add(1, Ordering::SeqCst); + if connected == 0 { + crate::drivers::keyboard::register_keyboard_listener(TTY.clone()); + + let current_task = scheduler::get_scheduler().current_task(); + current_task.attach(self.sref.upgrade().unwrap()); + } + + Ok(None) + } - let mut stdin = self.stdin.lock_irq(); + fn close(&self, _flags: aero_syscall::OpenFlags) { + self.connected.fetch_sub(1, Ordering::SeqCst); + } + + fn read_at(&self, flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> fs::Result { + let mut stdin = self.block_queue.wait( + WaitQueueFlags::from(flags) | WaitQueueFlags::DISABLE_IRQ, + &self.stdin, + |future| future.is_complete(), + )?; // record the back buffer size before swapping stdin.swap_buffer(); @@ -248,12 +272,9 @@ impl INodeInterface for Tty { } fn write_at(&self, _offset: usize, buffer: &[u8]) -> fs::Result { - let mut state = self.state.lock_irq(); - let mut performer = AnsiEscape; + let string = core::str::from_utf8(buffer).map_err(|_| FileSystemError::NotSupported)?; - for character in buffer.iter() { - state.parser.advance(&mut performer, *character); - } + crate::rendy::print!("{}", string); log::debug!("TTY::write_at(): {}", unsafe { core::str::from_utf8_unchecked(buffer) @@ -263,7 +284,9 @@ impl INodeInterface for Tty { } fn poll(&self, table: Option<&mut PollTable>) -> fs::Result { - table.map(|e| e.insert(&self.block_queue)); + if let Some(e) = table { + e.insert(&self.block_queue) + } let mut events = PollFlags::empty(); if self.stdin.lock_irq().is_complete() { @@ -331,7 +354,7 @@ impl devfs::Device for Tty { } fn device_name(&self) -> String { - String::from("tty") + String::from("vtty") } fn inode(&self) -> Arc { @@ -339,6 +362,16 @@ impl devfs::Device for Tty { } } +impl TerminalDevice for Tty { + fn attach(&self, _task: Arc) { + // FIXME: We should handle foreground groups in TTY aswell + } + + fn detach(&self, _task: Arc) { + // FIXME: TTY handle + } +} + #[cfg(target_arch = "x86_64")] impl KeyboardListener for Tty { fn on_key(&self, key: KeyCode, released: bool) { @@ -358,7 +391,7 @@ impl KeyboardListener for Tty { let mut shift = state.lshift || state.rshift; let ctrl = state.lctrl || state.rctrl; - if state.caps && state.caps { + if state.caps { shift = !shift; } @@ -397,11 +430,11 @@ impl KeyboardListener for Tty { if termios.c_lflag.contains(aero_syscall::TermiosLFlag::ICANON) { let mut stdin = self.stdin.lock_irq(); - if stdin.back_buffer.pop().is_some() { - if termios.c_lflag.contains(aero_syscall::TermiosLFlag::ECHO) { - rendy::backspace(); - stdin.cursor -= 1; - } + if stdin.back_buffer.pop().is_some() + && termios.c_lflag.contains(aero_syscall::TermiosLFlag::ECHO) + { + rendy::backspace(); + stdin.cursor -= 1; } } else { push_str("\x08"); @@ -433,7 +466,7 @@ impl KeyboardListener for Tty { } self.stdin.lock_irq().cursor = 0; - self.block_queue.notify_complete(); + self.block_queue.notify_all(); return; } @@ -442,14 +475,14 @@ impl KeyboardListener for Tty { KeyCode::KEY_ENTER | KeyCode::KEY_KPENTER if !released => { let mut stdin = self.stdin.lock_irq(); - stdin.back_buffer.push('\n' as u8); + stdin.back_buffer.push(b'\n'); stdin.cursor = 0; if termios.c_lflag.contains(aero_syscall::TermiosLFlag::ECHO) { rendy::print!("\n"); } - self.block_queue.notify_complete(); + self.block_queue.notify_all(); } KeyCode::KEY_BACKSPACE if !released => backspace(), @@ -500,376 +533,7 @@ impl KeyboardListener for Tty { } } -enum ParsedColor { - Unknown, - Foreground(u16), - Background(u16), +pub fn init() -> Result<(), FileSystemError> { + devfs::install_device(TTY.clone())?; + Ok(()) } - -const SGR_FOREGROUND_OFFSET_1: u16 = 30; -const SGR_BACKGROUND_OFFSET_1: u16 = 40; -const SGR_FOREGROUND_OFFSET_2: u16 = 90; -const SGR_BACKGROUND_OFFSET_2: u16 = 100; - -const ANSI_COLORS: &[u32; 8] = &[ - 0x00000000, // black - 0x00aa0000, // red - 0x0000aa00, // green - 0x00aa5500, // brown - 0x000000aa, // blue - 0x00aa00aa, // magenta - 0x0000aaaa, // cyan - 0x00aaaaaa, // grey -]; - -const ANSI_BRIGHT_COLORS: &[u32; 8] = &[ - 0x00555555, // black - 0x00ff5555, // red - 0x0055ff55, // green - 0x00ffff55, // brown - 0x005555ff, // blue - 0x00ff55ff, // magenta - 0x0055ffff, // cyan - 0x00ffffff, // grey -]; - -fn fixed_to_rgb(fixed: u16) -> u32 { - fixed as u32 -} - -struct AnsiEscape; - -impl vte::Perform for AnsiEscape { - fn print(&mut self, char: char) { - rendy::print!("{}", char); - } - - fn execute(&mut self, byte: u8) { - let char = byte as char; - - match char { - '\n' | '\t' => rendy::print!("{}", char), - - '\r' => { - let (_, y) = rendy::get_cursor_position(); - rendy::set_cursor_position(0, y) - } - - '\u{8}' => { - rendy::backspace(); - } - - _ => {} - } - } - - fn csi_dispatch( - &mut self, - params: &vte::Params, - _intermediates: &[u8], - ignore: bool, - action: char, - ) { - if ignore { - return; - } - - match action { - // Moves the cursor to row `n`, column `m`. The values are - // 1-based, and default to 1 (top left corner) if omitted. - 'H' | 'f' => { - let mut iter = params.iter(); - - let x = iter.next().unwrap_or(&[1])[0] as usize; - let y = iter.next().unwrap_or(&[1])[0] as usize; - - let mut x = if x != 0 { x - 1 } else { x }; - let mut y = if y != 0 { y - 1 } else { y }; - - let (rows, cols) = rendy::get_term_info(); - - // Make sure the provided coordinates are valid. - if x >= cols { - x = cols - 1; - } - - if y >= rows { - y = rows - 1; - } - - // Move the cursor to the position. - rendy::set_cursor_position(x, y); - } - - 'l' | 'h' => match params.iter().next() { - Some([25]) => { - // Disable the cursor if action == 'l` and enable it if action - // == 'h'. - rendy::set_cursor_visibility(action == 'h') - } - - _ => unimplemented!(), - }, - - // Clears parts of the screen. - 'J' => { - // If `n` is missing, it defaults to 0. - let n = params.iter().next().unwrap_or(&[0])[0] as usize; - - match n { - // If `n` is 0 (or missing), clear from cursor to end of screen. - 0 => { - let (x, y) = rendy::get_cursor_position(); - let (term_rows, term_cols) = rendy::get_rows_cols(); - - let rows_remaining = term_rows - (y + 1); - let cols_diff = term_cols - (x + 1); - let to_clear = rows_remaining * term_cols + cols_diff; - - rendy::set_auto_flush(false); - - for _ in 0..to_clear { - rendy::print!(" "); - } - - rendy::set_cursor_position(x, y); - rendy::double_buffer_flush(); - rendy::set_auto_flush(true); - } - - 1 => unimplemented!(), - - // If `n` is 2 or 3, clear the entire screen. - // - // TODO(Andy-Python-Programmer): When we support scrollback buffer, if `n` is - // 3, clear the entire scrollback buffer as well. - 2 | 3 => rendy::clear_screen(false), - - // Unknown value, do nothing. - _ => unimplemented!(), - } - } - - 'C' => { - // If `n` is missing, it defaults to 1. - let mut n = params.iter().next().unwrap_or(&[1])[0] as usize; - - let (x, y) = rendy::get_cursor_position(); - let (_, term_cols) = rendy::get_rows_cols(); - - if x + n > term_cols - 1 { - n = (term_cols - 1) - x; - } - - if n == 0 { - n = 1; - } - - rendy::set_cursor_position(x + n, y); - } - - 'K' => { - // If `n` is missing, it defaults to 0. - let n = params.iter().next().unwrap_or(&[0])[0] as usize; - - // NOTE: The cursor position does not change. - match n { - // If `n` is 0 (or missing), clear from cursor to the end of the line. - 0 => { - let (x, y) = rendy::get_cursor_position(); - let (_, term_cols) = rendy::get_rows_cols(); - - for _ in x..term_cols { - rendy::print!(" "); - } - - rendy::set_cursor_position(x, y); - } - - // If `n` is 1, clear from cursor to beginning of the line. - 1 => { - let (x, y) = rendy::get_cursor_position(); - - rendy::set_cursor_position(0, y); - - for _ in 0..x { - rendy::print!(" ") - } - } - - // If `n` is 2, clear entire line. - 2 => { - let (_, term_cols) = rendy::get_rows_cols(); - let (x, y) = rendy::get_cursor_position(); - - rendy::set_cursor_position(0, y); - - for _ in 0..term_cols { - rendy::print!(" ") - } - - rendy::set_cursor_position(x, y); - } - - _ => unimplemented!(), - } - } - - 'D' => { - // If `n` is missing, it defaults to 1. - let mut n = params.iter().next().unwrap_or(&[1])[0] as usize; - - let (x, y) = rendy::get_cursor_position(); - - // If the cursor is already at the edge of the screen, this has no effect. - if n > x { - n = x; - } - - if n == 0 { - n = 1; - } - - rendy::set_cursor_position(x - n, y); - } - - // Sets colors and style of the characters following this code. - 'm' => { - let mut piter = params.iter(); - let mut bright = false; - - while let Some(param) = piter.next() { - if !param.is_empty() { - let p1 = param[0]; - - match p1 { - // Reset or normal. All attributes off. - 0 => { - bright = false; - // TODO: Turn off dim. - - rendy::reset_default(); - } - - // Bold or increased intensity: - 1 => { - bright = true; - // TODO: Turn off dim. - } - - // Faint, decreased intensity, or dim. - 2 => { - // TODO: Turn on dim. - bright = false; - } - - code => { - let parsed_color = if code >= 30 && code <= 37 { - ParsedColor::Foreground(code - SGR_FOREGROUND_OFFSET_1) - } else if code >= 40 && code <= 47 { - ParsedColor::Background(code - SGR_BACKGROUND_OFFSET_1) - } else if code >= 90 && code <= 97 { - ParsedColor::Foreground(code - SGR_FOREGROUND_OFFSET_2) - } else if code >= 100 && code <= 107 { - ParsedColor::Background(code - SGR_BACKGROUND_OFFSET_2) - } else { - ParsedColor::Unknown - }; - - match parsed_color { - ParsedColor::Foreground(color) => { - let ccode = if bright { - ANSI_BRIGHT_COLORS[color as usize] - } else { - ANSI_COLORS[color as usize] - }; - - rendy::set_text_fg(ccode); - } - - ParsedColor::Background(color) => { - let ccode = if bright { - ANSI_BRIGHT_COLORS[color as usize] - } else { - ANSI_COLORS[color as usize] - }; - - rendy::set_text_bg(ccode); - } - - ParsedColor::Unknown => { - let parse_rgb = - |setter: fn(u32), piter: &mut vte::ParamsIter| { - let r = piter.next().unwrap_or(&[0])[0]; - let g = piter.next().unwrap_or(&[0])[0]; - let b = piter.next().unwrap_or(&[0])[0]; - - let color = - (r as u32) << 16 | (g as u32) << 8 | b as u32; - - setter(color); - }; - - let parse_fixed = - |setter: fn(u32), piter: &mut vte::ParamsIter| { - let fixed = piter.next().unwrap_or(&[0])[0]; - let color = fixed_to_rgb(fixed); - - setter(color); - }; - - let run_special_parser = - |setter: fn(u32), piter: &mut vte::ParamsIter| { - if let Some(arg_typee) = piter.next() { - let p1 = arg_typee[0]; - - match p1 { - // A colour number from 0 to 255, for use in 256-colour terminal - // environments. - // - // - Colours 0 to 7 are the `Black` to `White` variants respectively. - // - Colours 8 to 15 are brighter versions of the eight colours above. - // - Colours 16 to 231 contain several palettes of bright colours, - // - Colours 232 to 255 are shades of grey from black to white. - // - // [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg - 5 => parse_fixed(setter, piter), - - // A 24-bit RGB color, as specified by ISO-8613-3. - 2 => parse_rgb(setter, piter), - - _ => (), - } - } - }; - - // Background - if code == 48 { - run_special_parser(rendy::set_text_bg, &mut piter); - } - // Foreground - else if code == 38 { - run_special_parser(rendy::set_text_fg, &mut piter); - } - } - } - } - } - } - } - } - - _ => log::debug!("unknown action: {}", action), - } - } -} - -fn init_tty() { - // TODO: aarch64 port - #[cfg(target_arch = "x86_64")] - super::keyboard::register_keyboard_listener(TTY.as_ref().clone()); - - devfs::install_device(TTY.clone()).expect("failed to register tty as a device"); -} - -crate::module_init!(init_tty); diff --git a/src/aero_kernel/src/drivers/uart_16550.rs b/src/aero_kernel/src/drivers/uart_16550.rs index 6ff04d114e9..b646c2d8635 100644 --- a/src/aero_kernel/src/drivers/uart_16550.rs +++ b/src/aero_kernel/src/drivers/uart_16550.rs @@ -1,31 +1,34 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::fmt; use core::fmt::Write; use spin::Once; +use crate::arch::interrupts::{self, InterruptStack}; use crate::arch::io; +use crate::userland::task::Task; use crate::utils::sync::Mutex; -static COM_1: Once> = Once::new(); +use alloc::sync::Arc; +use alloc::vec::Vec; + +pub static COM_1: Once> = Once::new(); bitflags::bitflags! { pub struct InterruptEnable: u8 { @@ -37,6 +40,7 @@ bitflags::bitflags! { } bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] pub struct LineStatus: u8 { const INPUT_FULL = 1; const OUTPUT_EMPTY = 1 << 5; @@ -48,7 +52,7 @@ bitflags::bitflags! { pub struct SerialPort(u16); impl SerialPort { - #[inline(always)] + #[inline] pub const fn new(port: u16) -> Self { Self(port) } @@ -71,7 +75,7 @@ impl SerialPort { // Enable FIFO, clear TX/RX queues and set interrupt watermark at 14 bytes. io::outb(self.0 + 2, 0xC7); - // Mark data terminal ready, signal request to send and enable auxilliary + // Mark data terminal ready, signal request to send and enable auxiliary // output #2 (used as interrupt line for CPU). io::outb(self.0 + 4, 0x0B); @@ -91,30 +95,40 @@ impl SerialPort { fn wait_for_line_status(&self, line_status: LineStatus) { while !self.line_status().contains(line_status) { - core::hint::spin_loop() + core::hint::spin_loop(); } } pub fn send_byte(&mut self, byte: u8) { - unsafe { - match byte { - 8 | 0x7F => { - self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + match byte { + 8 | 0x7F => { + self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + unsafe { io::outb(self.0, 8); + } - self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + unsafe { io::outb(self.0, b' '); + } - self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + unsafe { io::outb(self.0, 8); } - _ => { - self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); - io::outb(self.0, byte) + } + _ => { + self.wait_for_line_status(LineStatus::OUTPUT_EMPTY); + unsafe { + io::outb(self.0, byte); } } } } + + pub fn read_byte(&mut self) -> u8 { + unsafe { io::inb(self.0) } + } } impl fmt::Write for SerialPort { @@ -127,15 +141,44 @@ impl fmt::Write for SerialPort { } } -/// Initialize the serial ports if avaliable. +fn irq_handler(_stack: &mut InterruptStack) { + if !unsafe { COM_1.get_unchecked() } + .lock_irq() + .line_status() + .contains(LineStatus::INPUT_FULL) + { + return; + } + + (*LISTENERS) + .lock_irq() + .iter() + .for_each(|task| task.wake_up()); +} + +lazy_static::lazy_static! { + static ref LISTENERS: Mutex>> = Mutex::new(Vec::new()); +} + +pub fn register_listener(task: Arc) { + (*LISTENERS).lock_irq().push(task); +} + +/// Initialize the serial ports if available. pub fn init() { unsafe { - let com_1 = SerialPort::new(0x3F8).init(); - + let com_1 = SerialPort::new(0x3f8).init(); COM_1.call_once(move || Mutex::new(com_1)); } } +pub fn setup_interrupts() { + let vector = interrupts::allocate_vector(); + interrupts::register_handler(vector, irq_handler); + + crate::arch::apic::io_apic_setup_legacy_irq(4, vector, 1); +} + pub macro serial_print($($arg:tt)*) { crate::drivers::uart_16550::_serial_print(format_args!($($arg)*)) } @@ -147,9 +190,9 @@ pub macro serial_println { #[doc(hidden)] pub fn _serial_print(args: fmt::Arguments) { - COM_1.get().map(|c| { + if let Some(c) = COM_1.get() { c.lock_irq() .write_fmt(args) .expect("failed to write to COM1") - }); + } } diff --git a/src/aero_kernel/src/drivers/uart_pl011.rs b/src/aero_kernel/src/drivers/uart_pl011.rs index 26497aa0d11..ecce06cfb5f 100644 --- a/src/aero_kernel/src/drivers/uart_pl011.rs +++ b/src/aero_kernel/src/drivers/uart_pl011.rs @@ -1,23 +1,21 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -// REFRENCE: PrimeCell UART (PL011) Technical Reference Manual +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +// REFERENCE: PrimeCell UART (PL011) Technical Reference Manual use core::fmt; use core::fmt::Write; diff --git a/src/aero_kernel/src/emu.rs b/src/aero_kernel/src/emu.rs index d4810f54560..bef1869d8d9 100644 --- a/src/aero_kernel/src/emu.rs +++ b/src/aero_kernel/src/emu.rs @@ -1,3 +1,20 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + use crate::utils::io; #[repr(u32)] diff --git a/src/aero_kernel/src/fs/block.rs b/src/aero_kernel/src/fs/block.rs deleted file mode 100644 index 726d6bd8337..00000000000 --- a/src/aero_kernel/src/fs/block.rs +++ /dev/null @@ -1,181 +0,0 @@ -use core::alloc::Layout; - -use alloc::alloc::alloc_zeroed; -use alloc::collections::BTreeMap; -use alloc::sync::{Arc, Weak}; -use alloc::vec::Vec; - -use crate::fs::devfs::install_device; -use crate::fs::Result; - -use crate::mem::paging::VirtAddr; -use crate::utils::sync::Mutex; - -use super::devfs::{alloc_device_marker, Device}; -use super::inode::INodeInterface; - -pub trait BlockDeviceInterface: Send + Sync { - fn read(&self, sector: usize, dest: &mut [u8]) -> Option; - fn write(&self, sector: usize, buf: &[u8]) -> Option; -} - -static BLOCK_DEVS: Mutex>> = Mutex::new(BTreeMap::new()); - -/// Installs the provided block `device` into the filesyetm. -pub fn install_block_device(dev: Arc) -> Result<()> { - let mut devs = BLOCK_DEVS.lock(); - install_device(dev.clone())?; - - log::debug!("block: installed block device {}", dev.name()); - devs.insert(dev.id, dev); - - Ok(()) -} - -pub struct BlockDevice { - id: usize, - name: String, - dev: Arc, - self_ref: Weak, -} - -impl BlockDevice { - pub fn new(name: String, imp: Arc) -> Arc { - Arc::new_cyclic(|me| BlockDevice { - id: alloc_device_marker(), - name, - dev: imp, - self_ref: me.clone(), - }) - } - - pub fn name(&self) -> String { - self.name.clone() - } -} - -impl INodeInterface for BlockDevice {} - -impl Device for BlockDevice { - fn device_marker(&self) -> usize { - self.id - } - - fn device_name(&self) -> String { - self.name() - } - - fn inode(&self) -> Arc { - self.self_ref.upgrade().unwrap().clone() - } -} - -pub trait RawAccess: Send + Sync { - fn read_direct(&self, addr: usize, dest: &mut [u8]) -> Option; - fn write_direct(&self, addr: usize, buf: &[u8]) -> Option; -} - -impl BlockDeviceInterface for T { - fn read(&self, sector: usize, dest: &mut [u8]) -> Option { - self.read_direct(sector * 512, dest) - } - - fn write(&self, sector: usize, buf: &[u8]) -> Option { - self.write_direct(sector * 512, buf) - } -} - -impl RawAccess for BlockDevice { - fn read_direct(&self, offset: usize, dest: &mut [u8]) -> Option { - assert_eq!(offset % 512, 0); - self.dev.read(offset / 512, dest) - } - - fn write_direct(&self, offset: usize, buf: &[u8]) -> Option { - assert_eq!(offset % 512, 0); - self.dev.write(offset / 512, buf) - } -} - -pub struct Mbr { - data: VirtAddr, -} - -impl Mbr { - pub fn new() -> Self { - let layout = unsafe { Layout::from_size_align_unchecked(512, 0x1000) }; - let memory = unsafe { alloc_zeroed(layout) }; - - Self { - data: VirtAddr::new(memory as u64), - } - } - - pub fn bytes(&self) -> &[u8] { - self.bytes_mut() - } - - pub fn bytes_mut(&self) -> &mut [u8] { - unsafe { core::slice::from_raw_parts_mut(self.data.as_mut_ptr(), 512) } - } - - pub fn is_valid(&self) -> bool { - self.bytes()[510..] == [0x55, 0xAA] - } - - pub fn partition(&self, idx: usize) -> Option { - if idx >= 4 { - return None; - } - let off = 0x01BEusize + 0x10 * idx; - - Some(Partition { - data: &self.bytes()[off..off + 16], - }) - } -} - -pub struct Partition<'a> { - data: &'a [u8], -} - -impl Partition<'_> { - pub fn total_sectors(&self) -> u32 { - unsafe { *(self.data.as_ptr().offset(12) as *const u32) } - } -} - -pub fn launch() -> Result<()> { - // NOTE: Copy all of the block devices into a vector since we will - // need to lock the BLOCK_DEVS static when iterating which will - // cause a deadlock. - let mut blocks_copy = Vec::>::new(); - - for (_, device) in BLOCK_DEVS.lock().iter() { - blocks_copy.push(device.clone()); - } - - for block in blocks_copy { - let mbr = Mbr::new(); - - block.read(0, mbr.bytes_mut()); - log::debug!("{:?}", mbr.bytes_mut()); - - if mbr.is_valid() { - log::info!("{}: found MBR partition", block.name()); - - for p in 0..4 { - if let Some(part) = mbr.partition(p) { - if part.total_sectors() > 0 { - let name = alloc::format!("{}p{}", block.name(), p); - let block_device = BlockDevice::new(name, block.clone()); - - install_block_device(block_device)?; - } - } - } - } - } - - Ok(()) -} diff --git a/src/aero_kernel/src/fs/block/gpt.rs b/src/aero_kernel/src/fs/block/gpt.rs new file mode 100644 index 00000000000..ee94ad652be --- /dev/null +++ b/src/aero_kernel/src/fs/block/gpt.rs @@ -0,0 +1,159 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use crate::fs::block::BlockDeviceInterface; + +use super::BlockDevice; +use core::mem::MaybeUninit; + +use alloc::boxed::Box; + +const GPT_TABLE_SIGNATURE: u64 = 0x5452_4150_2049_4645; + +#[repr(C)] +pub struct GptTableHeader { + pub signature: u64, + pub revision: u32, + pub header_size: u32, + pub header_checksum: u32, + pub reserved_zero: u32, + pub current_lba: u64, + pub backup_lba: u64, + pub first_lba: u64, + pub last_lba: u64, + pub disk_guid: [u8; 16], + /// Starting LBA of array of partition entries (usually `2` for compatibility). + pub starting_lba: u64, + pub num_entries: u32, + pub entry_size: u32, + pub table_checksum: u32, + pub padding: [u8; 420], +} + +const_assert_eq!(core::mem::size_of::(), 512); + +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(C)] +pub struct GptGuid { + a: u32, + b: u16, + c: u16, + d: [u8; 2], + e: [u8; 6], +} + +impl GptGuid { + pub const NULL: GptGuid = GptGuid { + a: 0, + b: 0, + c: 0, + d: [0; 2], + e: [0; 6], + }; +} + +const_assert_eq!(core::mem::size_of::(), 16); + +#[derive(Debug)] +#[repr(C)] +pub struct GptEntry { + type_guid: GptGuid, + unique_guid: GptGuid, + first_lba: u64, + last_lba: u64, + attr_flags: u64, + partition_name: [u8; 72], +} + +impl GptEntry { + pub fn start_lba(&self) -> u64 { + self.first_lba + } + + pub fn size(&self) -> u64 { + self.last_lba - self.first_lba + } + + pub fn partition_name(&self) -> String { + let mut result = String::new(); + + // UEFI strings are UCS-2, not UTF-16. That means that each + // source character is exactly two bytes long. + for i in (0..self.partition_name.len()).step_by(2) { + let upper = u16::from(self.partition_name[i + 1]) << 8; + let c = upper | u16::from(self.partition_name[i]); + + // Encountered a null character, so we're done. + if c == 0 { + break; + } + + result.push(char::try_from(u32::from(c)).unwrap_or('�')); + } + + result + } + + pub fn is_used(&self) -> bool { + self.type_guid != GptGuid::NULL + } +} + +const_assert_eq!(core::mem::size_of::(), 128); + +pub struct Gpt { + entries: Box<[GptEntry]>, +} + +impl Gpt { + pub fn new(controller: &BlockDevice) -> Option { + // Get the GPT header. + let mut header = Box::::new_uninit(); + + controller + .read_block(1, header.as_bytes_mut()) + .expect("gpt: failed to read first sector"); + + // SAFETY: The buffer is initialized above. + let header = unsafe { header.assume_init() }; + + if header.signature != GPT_TABLE_SIGNATURE { + return None; + } + + let entry_size = header.entry_size as usize; + assert_eq!(entry_size, core::mem::size_of::()); + + let mut entry_list = Box::<[GptEntry]>::new_uninit_slice(header.num_entries as usize); + + controller + .read_block( + header.starting_lba as _, + MaybeUninit::slice_as_bytes_mut(&mut entry_list), + ) + .expect("gpt: failed to read entry list"); + + // SAFETY: The entries list is initialized above. + let entries = unsafe { entry_list.assume_init() }; + + Some(Self { entries }) + } + + pub fn entries(&self) -> &[GptEntry] { + &self.entries + } +} diff --git a/src/aero_kernel/src/fs/block/mod.rs b/src/aero_kernel/src/fs/block/mod.rs new file mode 100644 index 00000000000..de037d41a1e --- /dev/null +++ b/src/aero_kernel/src/fs/block/mod.rs @@ -0,0 +1,492 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +mod gpt; + +use gpt::Gpt; + +use core::mem::MaybeUninit; +use core::ops::{Deref, DerefMut}; +use core::sync::atomic::{AtomicBool, Ordering}; + +use alloc::collections::BTreeMap; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; + +use crate::fs::devfs::install_device; +use crate::fs::{FileSystem, Result}; + +use crate::fs::ext2::Ext2; +use crate::mem::paging::*; +use crate::mem::AddressSpace; +use crate::utils::sync::Mutex; + +use super::cache::{Cache, CacheArc, CacheItem, Cacheable}; +use super::devfs::{alloc_device_marker, Device}; +use super::inode::INodeInterface; + +type PageCacheKey = (usize, usize); // (owner ptr, index) +pub type PageCacheItem = CacheArc>; + +struct DirtyMapping { + addr_space: AddressSpace, + addr: VirtAddr, +} + +pub struct CachedPage { + owner: Weak, + offset: usize, + page: PhysFrame, + dirty: AtomicBool, + dirty_mappings: Mutex>, +} + +impl CachedPage { + fn new(owner: Weak, offset: usize) -> Self { + let k = Self { + owner, + offset, + page: FRAME_ALLOCATOR + .allocate_frame() + .expect("page_cache: out of memory"), + dirty: AtomicBool::new(false), + dirty_mappings: Mutex::new(Vec::new()), + }; + // TODO: temporary hack. i mean this is fine but is there a cleaner way to do this. this is + // required since when the VM for the process umaps a page that contains a cached page, it + // will unmap this page which will decrease the refcnt to 0 and deallocate it. + get_vm_frames().unwrap()[k.page.start_address().as_u64() as usize / 4096usize] + .inc_ref_count(); + k + } + + fn data_mut(&self) -> &mut [MaybeUninit] { + let data_ptr = self + .page + .start_address() + .as_hhdm_virt() + .as_mut_ptr::>(); + + // SAFETY: It is safe to create a slice of MaybeUninit because it has the same + // size and alignment as T. + unsafe { core::slice::from_raw_parts_mut(data_ptr, Size4KiB::SIZE as usize) } + } + + pub fn data_addr(&self) -> PhysAddr { + self.page.start_address() + } + + pub fn page(&self) -> PhysFrame { + self.page + } + + fn make_key(device: &Weak, offset: usize) -> PageCacheKey { + (device.as_ptr().addr(), offset) + } + + /// Returns whether the page has been marked dirty. + fn is_dirty(&self) -> bool { + self.dirty.load(Ordering::SeqCst) + } + + pub fn mark_dirty(&self) { + self.dirty.store(true, Ordering::SeqCst); + } + + fn device(&self) -> Arc { + self.owner.upgrade().unwrap() + } + + fn sync(&self) { + if !self.is_dirty() { + return; + } + + // Commit the changes made to the cache to the owner. + let owner = self.device(); + let offset_bytes = self.offset * Size4KiB::SIZE as usize; + owner.write_direct(offset_bytes, self.page); + + for mut mapping in self.dirty_mappings.lock_irq().drain(..) { + let mut offset_table = mapping.addr_space.offset_page_table(); + offset_table + .unmap(Page::::containing_address(mapping.addr)) + .unwrap() + .1 + .flush(); + } + + self.dirty.store(false, Ordering::SeqCst); + } +} + +impl Drop for CachedPage { + fn drop(&mut self) { + self.sync() + } +} + +impl Cacheable for CachedPage { + fn cache_key(&self) -> PageCacheKey { + Self::make_key(&self.owner, self.offset) + } +} + +lazy_static::lazy_static! { + pub(in crate::fs) static ref PAGE_CACHE: Arc> = Cache::new(); +} + +impl Cache { + /// Returns the cached page at the given offset, if not present, it will be allocated, + /// initialized with the data on the disk and placed in the page cache. + /// + /// ## Arguments + /// + /// * `device` - The device to get the page from. + /// * `offset` - The offset in bytes to the data. This will be rounded down to the nearest page + /// boundary. + pub fn get_page(&self, device: &Weak, offset: usize) -> PageCacheItem { + let cache_offset = offset / Size4KiB::SIZE as usize; + let cache_key = CachedPage::make_key(device, cache_offset); + + if let Some(page) = PAGE_CACHE.get(cache_key) { + return page; + } + + let page = CachedPage::new(device.clone(), cache_offset); + let device = device.upgrade().expect("page_cache: device dropped"); + + let aligned_offset = align_down(offset as u64, Size4KiB::SIZE) as usize; + device + .read_direct(aligned_offset, page.page()) + .expect("page_cache: failed to read block"); + + PAGE_CACHE.make_item_cached(page) + } +} + +// TODO: cache hit miss stats + +pub struct DirtyRef { + cache: PageCacheItem, + ptr: *mut T, +} + +impl DirtyRef { + pub fn new(device: &Weak, offset: usize) -> Self { + let cache = PAGE_CACHE.get_page(device, offset); + + let ptr_offset = offset % Size4KiB::SIZE as usize; + let ptr = &cache.data_mut()[ptr_offset..ptr_offset + core::mem::size_of::()]; + + Self { + ptr: ptr.as_ptr() as *mut T, + cache, + } + } +} + +impl Deref for DirtyRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.ptr } + } +} + +impl DerefMut for DirtyRef { + fn deref_mut(&mut self) -> &mut Self::Target { + self.cache.mark_dirty(); + unsafe { &mut *self.ptr } + } +} + +unsafe impl Sync for DirtyRef {} +unsafe impl Send for DirtyRef {} + +pub trait BlockDeviceInterface: Send + Sync { + fn block_size(&self) -> usize; + + fn read_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option; + fn write_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option; + + fn read_block(&self, sector: usize, dest: &mut [MaybeUninit]) -> Option; + fn write_block(&self, sector: usize, buf: &[u8]) -> Option; +} + +pub trait CachedAccess: Send + Sync { + fn sref(&self) -> Weak; + + fn read_direct(&self, offset: usize, dest: PhysFrame) -> Option; + fn write_direct(&self, offset: usize, src: PhysFrame) -> Option; + + fn read(&self, mut offset: usize, dest: &mut [MaybeUninit]) -> Option { + let mut loc = 0; + + while loc < dest.len() { + let page = PAGE_CACHE.get_page(&self.sref(), offset); + + let page_offset = offset % Size4KiB::SIZE as usize; + let size = core::cmp::min(Size4KiB::SIZE as usize - page_offset, dest.len() - loc); + + let data = &page.data_mut()[page_offset..page_offset + size]; + dest[loc..loc + size].copy_from_slice(data); + + core::mem::forget(page); + + loc += size; + offset = align_down(offset as u64 + Size4KiB::SIZE, Size4KiB::SIZE) as usize; + } + + Some(loc) + } + + /// Writes the given data to the device at the given offset and returns the + /// number of bytes written. + /// + /// ## Notes + /// + /// * This function does **not** sync the written data to the disk. + fn write(&self, mut offset: usize, buffer: &[u8]) -> Option { + let mut loc = 0; + + while loc < buffer.len() { + // TODO: If it is not found in the page cache, then, when the write perfectly falls on + // page size boundaries, the page is not even read from disk, but allocated and + // immediately marked dirty. + let page = PAGE_CACHE.get_page(&self.sref(), offset); + + let page_offset = offset % Size4KiB::SIZE as usize; + let size = core::cmp::min(Size4KiB::SIZE as usize - page_offset, buffer.len() - loc); + + MaybeUninit::copy_from_slice( + &mut page.data_mut()[page_offset..page_offset + size], + &buffer[loc..loc + size], + ); + + page.mark_dirty(); + page.sync(); + + loc += size; + offset = align_down(offset as u64 + Size4KiB::SIZE, Size4KiB::SIZE) as usize; + } + + Some(loc) + } +} + +static BLOCK_DEVS: Mutex>> = Mutex::new(BTreeMap::new()); + +/// Installs the provided block `device` into the filesyetm. +pub fn install_block_device(dev: Arc) -> Result<()> { + let mut devs = BLOCK_DEVS.lock(); + install_device(dev.clone())?; + + log::debug!("block: installed block device {}", dev.name()); + devs.insert(dev.id, dev); + + Ok(()) +} + +pub struct BlockDevice { + id: usize, + name: String, + dev: Arc, + sref: Weak, +} + +impl BlockDevice { + pub fn new(name: String, imp: Arc) -> Arc { + Arc::new_cyclic(|sref| BlockDevice { + id: alloc_device_marker(), + name, + dev: imp, + sref: sref.clone(), + }) + } + + pub fn name(&self) -> String { + self.name.clone() + } +} + +impl BlockDeviceInterface for BlockDevice { + fn block_size(&self) -> usize { + self.dev.block_size() + } + + fn read_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option { + self.dev.read_dma(sector, start, size) + } + + fn write_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option { + self.dev.write_dma(sector, start, size) + } + + fn read_block(&self, sector: usize, dest: &mut [MaybeUninit]) -> Option { + self.dev.read_block(sector, dest) + } + + fn write_block(&self, sector: usize, buf: &[u8]) -> Option { + self.dev.write_block(sector, buf) + } +} + +impl CachedAccess for BlockDevice { + fn sref(&self) -> Weak { + self.sref.clone() + } + + fn read_direct(&self, offset: usize, dest: PhysFrame) -> Option { + self.dev.read_dma( + offset / self.dev.block_size(), + dest.start_address(), + Size4KiB::SIZE as _, + ) + } + + fn write_direct(&self, offset: usize, src: PhysFrame) -> Option { + self.dev.write_dma( + offset / self.dev.block_size(), + src.start_address(), + Size4KiB::SIZE as _, + ) + } +} + +impl INodeInterface for BlockDevice {} + +impl Device for BlockDevice { + fn device_marker(&self) -> usize { + self.id + } + + fn device_name(&self) -> String { + self.name() + } + + fn inode(&self) -> Arc { + self.sref.upgrade().unwrap() + } +} + +struct PartitionBlockDevice { + offset: usize, // offset in sectors + size: usize, // capacity in sectors + device: Arc, +} + +impl PartitionBlockDevice { + fn new(offset: usize, size: usize, device: Arc) -> Arc { + Arc::new(Self { + offset, + size, + device, + }) + } +} + +impl BlockDeviceInterface for PartitionBlockDevice { + fn read_block(&self, sector: usize, dest: &mut [MaybeUninit]) -> Option { + if sector >= self.size { + return None; + } + + self.device.read_block(self.offset + sector, dest) + } + + fn write_block(&self, sector: usize, buf: &[u8]) -> Option { + if sector >= self.size { + return None; + } + + self.device.write_block(self.offset + sector, buf) + } + + fn write_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option { + if sector >= self.size { + return None; + } + + self.device.write_dma(self.offset + sector, start, size) + } + + fn read_dma(&self, sector: usize, start: PhysAddr, size: usize) -> Option { + if sector >= self.size { + return None; + } + + self.device.read_dma(self.offset + sector, start, size) + } + + fn block_size(&self) -> usize { + self.device.block_size() + } +} + +pub fn launch() -> Result<()> { + let mut blocks_copy = Vec::>::new(); + + for (_, device) in BLOCK_DEVS.lock().iter() { + blocks_copy.push(device.clone()); + } + + for block in blocks_copy { + if let Some(gpt) = Gpt::new(&block) { + log::info!("block: found GPT on {}!", block.name()); + + for (i, entry) in gpt + .entries() + .iter() + .enumerate() + .filter(|(_, e)| e.is_used()) + { + let start = entry.start_lba() as usize; + let size = entry.size() as usize; + + log::info!( + "gpt: found partition (name=`{}`, start={:#x}, size{:#x})!", + entry.partition_name(), + start, + size + ); + + let name = alloc::format!("{}p{}", block.name(), i); + let partition_device = PartitionBlockDevice::new(start, size, block.clone()); + let device = BlockDevice::new(name, partition_device); + + install_block_device(device.clone())?; + + // Check what filesystem is on this partition and mount it. + if let Some(ext2) = Ext2::new(device.clone()) { + log::info!("gpt: found ext2 filesystem on {}!", device.name()); + + super::ROOT_FS.call_once(|| ext2.clone()); + super::ROOT_DIR.call_once(|| ext2.root_dir()); + } + } + } + } + + super::devfs::init()?; + log::info!("installed devfs"); + + super::procfs::init()?; + log::info!("installed procfs"); + + Ok(()) +} diff --git a/src/aero_kernel/src/fs/cache.rs b/src/aero_kernel/src/fs/cache.rs index 46512ec006e..64fa5c84837 100644 --- a/src/aero_kernel/src/fs/cache.rs +++ b/src/aero_kernel/src/fs/cache.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! General implementation for file system caching. Stuff like inode needs to be cached //! to improve performance and in this case looking up inode data from an IO device such @@ -28,19 +26,23 @@ use core::borrow::Borrow; use core::fmt::Debug; use core::hash::Hash; +use core::num::NonZeroUsize; use core::ops; +use core::sync::atomic::{AtomicBool, Ordering}; -use alloc::sync::Arc; -use alloc::sync::Weak; +use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; use spin::Once; use crate::fs::inode::{DirEntry, INodeInterface}; -use crate::utils::sync::Mutex; +use crate::utils::sync::BMutex; -pub(super) static INODE_CACHE: Once> = Once::new(); -pub(super) static DIR_CACHE: Once> = Once::new(); +use super::path::PathBuf; +use super::FileSystem; + +pub static INODE_CACHE: Once> = Once::new(); +pub static DIR_CACHE: Once> = Once::new(); // NOTE: We require a custom wrapper around [`Arc`] and [`Weak`] since we need to be able // to move the cache item from the used list to the unused list when the cache item is dropped. @@ -144,22 +146,30 @@ pub trait Cacheable: Sized { fn cache_key(&self) -> K; } -/// Structure representing a cache item in the cache index. See the documentation of [CacheIndex] -/// and the fields of this struct for more information. pub struct CacheItem> { cache: Weak>, value: V, + /// Whether the cache item has active strong references associated + /// with it. + used: AtomicBool, } impl> CacheItem { - /// Constructs a new `CacheItem`. - #[inline] pub fn new(cache: &Weak>, value: V) -> CacheArc { CacheArc::new(Self { cache: cache.clone(), value, + used: AtomicBool::new(false), }) } + + pub fn is_used(&self) -> bool { + self.used.load(Ordering::SeqCst) + } + + pub fn set_used(&self, yes: bool) { + self.used.store(yes, Ordering::SeqCst); + } } impl> ops::Deref for CacheItem { @@ -174,33 +184,37 @@ unsafe impl> Sync for CacheItem {} struct CacheIndex> { used: hashbrown::HashMap>>, + /// Cache items that are longer have any active strong references associated + /// with them. These are stored in the cache index so, if the item is + /// accessed again, we can re-use it; reducing required memory allocation + /// and I/O (if applicable). + unused: lru::LruCache>>, } -/// Structure representing a cache with a key of `K` and value of `V`. The cache -/// key is used to get the cache from the cache index. This structure basically contains -/// the cache index (protected by a mutex) and a weak self reference to itself. pub struct Cache> { - index: Mutex>, + index: BMutex>, self_ref: Weak>, } impl> Cache { - pub(super) fn new() -> Arc { + pub fn new() -> Arc { Arc::new_cyclic(|this| Cache:: { - index: Mutex::new(CacheIndex { + index: BMutex::new(CacheIndex { used: hashbrown::HashMap::new(), + unused: lru::LruCache::new(NonZeroUsize::new(4096).unwrap()), }), self_ref: this.clone(), }) } - pub(super) fn clear(&self) { + pub fn clear(&self) { let mut index_mut = self.index.lock(); + index_mut.unused.clear(); index_mut.used.clear(); } - pub(super) fn make_item_cached(&self, value: V) -> CacheArc> { + pub fn make_item_cached(&self, value: V) -> CacheArc> { let item = CacheItem::::new(&self.self_ref, value); self.index @@ -208,51 +222,86 @@ impl> Cache { .used .insert(item.cache_key(), Arc::downgrade(&item)); + item.set_used(true); item } - pub(super) fn make_item_no_cache(&self, value: V) -> CacheArc> { + pub fn make_item_no_cache(&self, value: V) -> CacheArc> { CacheItem::::new(&Weak::default(), value) } - pub(super) fn get(&self, key: K) -> Option>> { - let index = self.index.lock(); + pub fn get(&self, key: K) -> Option>> { + let mut index = self.index.lock(); if let Some(entry) = index.used.get(&key) { - Some(CacheArc::from(entry.upgrade()?)) + let entry = entry.upgrade()?; + Some(CacheArc::from(entry)) + } else if let Some(entry) = index.unused.pop(&key) { + entry.set_used(true); + index.used.insert(key, Arc::downgrade(&entry)); + + Some(entry.into()) } else { None } } + pub fn rehash(&self, item: CacheArc>, update: F) + where + F: FnOnce(), + { + let mut index = self.index.lock(); + let key = item.cache_key(); + + index.used.remove(&key).expect("cache: item is not used"); + update(); + + let new_key = item.cache_key(); + index.used.insert(new_key, Arc::downgrade(&item)); + } + pub fn log(&self) { + let index = self.index.lock(); + log::debug!("Cache:"); - log::debug!("\t Used entries: {}", self.index.lock().used.len()); - for item in self.index.lock().used.iter() { - log::debug!("\t\t {:?} -> {:?}", item.0, item.1.strong_count()); + log::debug!("\t Used entries: {}", index.used.len()); + for (key, item) in index.used.iter() { + log::debug!("\t\t {:?} -> {:?}", key, item.strong_count()); + } + + log::debug!("\t Unused entries: {}", index.unused.len()); + for (key, item) in index.unused.iter() { + log::debug!("\t\t {:?} -> {:?}", key, Arc::strong_count(item)) } } /// Removes the item with the provided `key` from the cache. - pub(super) fn remove(&self, key: &K) { + pub fn remove(&self, key: &K) { let mut index = self.index.lock(); - index.used.remove(key); + if index.used.remove(key).is_none() { + let _ = index.unused.pop(key); + } } fn mark_item_unused(&self, item: CacheArc>) { - let mut this = self.index.lock(); + item.set_used(false); + + let mut index = self.index.lock(); let key = item.cache_key(); - this.used.remove(&key); + index.used.remove(&key); + index.unused.put(key, item.0.clone()); } } impl> CacheDropper for CacheItem { fn drop_this(&self, this: Arc) { if let Some(cache) = self.cache.upgrade() { - cache.mark_item_unused(this.into()); + if self.is_used() { + cache.mark_item_unused(this.into()); + } } } } @@ -262,13 +311,18 @@ pub type INodeCache = Cache; pub type INodeCacheItem = CacheArc>; pub type INodeCacheWeakItem = CacheWeak>; -/// The cache key for the directory entry cache used to get the cache item. The cache key -/// is the tuple of the parent's cache marker (akin [usize]) and the name of the directory entry -/// (akin [String]). pub type DirCacheKey = (usize, String); pub type DirCache = Cache; pub type DirCacheItem = CacheArc>; +impl Debug for DirCacheItem { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("DirCacheItem") + .field(&self.absolute_path()) + .finish() + } +} + pub struct CachedINode(Arc); impl CachedINode { @@ -291,10 +345,13 @@ impl ops::Deref for CachedINode { impl Cacheable for CachedINode { fn cache_key(&self) -> INodeCacheKey { - ( - Weak::as_ptr(&self.weak_filesystem().unwrap()) as *const () as usize, - self.metadata().unwrap().id, - ) + INodeCacheItem::make_key(self.weak_filesystem().unwrap(), self.metadata().unwrap().id) + } +} + +impl INodeCacheItem { + pub fn make_key(fs: Weak, id: usize) -> INodeCacheKey { + (Weak::as_ptr(&fs).addr(), id) } } @@ -311,14 +368,14 @@ impl Cacheable for DirEntry { } pub trait DirCacheImpl { - fn absolute_path_str(&self) -> String; + fn absolute_path(&self) -> PathBuf; } impl DirCacheImpl for DirCacheItem { - fn absolute_path_str(&self) -> String { + fn absolute_path(&self) -> PathBuf { let mut current_entry = Some(self.clone()); let mut path_nodes = Vec::new(); - let mut result = String::new(); + let mut result = PathBuf::new(); // We need to collect all of the path nodes, reverse them and then join them // with the path separator. @@ -328,12 +385,13 @@ impl DirCacheImpl for DirCacheItem { } for node in path_nodes.iter().rev() { - result.push_str(node); + result.push(node.as_str()); + // result.push_str(node); - // If we are not at the root node, we need to add the path separator. - if node != "/" { - result.push('/'); - } + // // If we are not at the root node, we need to add the path separator. + // if node != "/" { + // result.push('/'); + // } } result @@ -342,12 +400,16 @@ impl DirCacheImpl for DirCacheItem { #[inline] pub fn clear_inode_cache() { - INODE_CACHE.get().map(|cache| cache.clear()); + if let Some(cache) = INODE_CACHE.get() { + cache.clear() + } } #[inline] pub fn clear_dir_cache() { - DIR_CACHE.get().map(|cache| cache.clear()); + if let Some(cache) = DIR_CACHE.get() { + cache.clear() + } } pub fn icache() -> &'static Arc { @@ -364,6 +426,6 @@ pub fn dcache() -> &'static Arc { /// This function is responsible for initializing the inode cache. pub fn init() { - INODE_CACHE.call_once(|| INodeCache::new()); - DIR_CACHE.call_once(|| DirCache::new()); + INODE_CACHE.call_once(INodeCache::new); + DIR_CACHE.call_once(DirCache::new); } diff --git a/src/aero_kernel/src/fs/devfs.rs b/src/aero_kernel/src/fs/devfs.rs index ccb6d43d68d..016364ddb20 100644 --- a/src/aero_kernel/src/fs/devfs.rs +++ b/src/aero_kernel/src/fs/devfs.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! The `/dev` directory contains the special device files for all the devices. @@ -27,19 +25,18 @@ use alloc::sync::Arc; use spin::{Once, RwLock}; -use crate::fs::lookup_path; -use crate::fs::Path; +use crate::fs::{lookup_path, Path}; use crate::logger; use crate::mem::paging::*; use crate::rendy::RendyInfo; use super::cache::{DirCacheItem, INodeCacheItem}; -use super::inode::{INodeInterface, PollFlags, PollTable}; +use super::inode::{INodeInterface, MMapPage, PollFlags, PollTable}; use super::ramfs::RamFs; -use super::FileSystemError; -use super::{FileSystem, Result, MOUNT_MANAGER}; +use super::{FileSystem, FileSystemError, Result, MOUNT_MANAGER}; -use aero_syscall::{prelude::*, MMapFlags}; +use aero_syscall::prelude::*; +use aero_syscall::{MMapFlags, OpenFlags}; lazy_static::lazy_static! { pub static ref DEV_FILESYSTEM: Arc = DevFs::new(); @@ -116,8 +113,8 @@ impl INodeInterface for DevINode { self.0.inode().write_at(offset, buffer) } - fn read_at(&self, offset: usize, buffer: &mut [u8]) -> Result { - self.0.inode().read_at(offset, buffer) + fn read_at(&self, flags: OpenFlags, offset: usize, buffer: &mut [u8]) -> Result { + self.0.inode().read_at(flags, offset, buffer) } fn mmap(&self, offset: usize, size: usize, flags: MMapFlags) -> Result { @@ -131,6 +128,14 @@ impl INodeInterface for DevINode { fn poll(&self, table: Option<&mut PollTable>) -> Result { self.0.inode().poll(table) } + + fn open(&self, handle: Arc) -> Result> { + self.0.inode().open(handle) + } + + fn mmap_v2(&self, offset: usize) -> Result { + self.0.inode().mmap_v2(offset) + } } /// Implementation of dev filesystem. (See the module-level documentation for more @@ -173,12 +178,16 @@ impl Device for DevNull { } impl INodeInterface for DevNull { - fn read_at(&self, _offset: usize, _buffer: &mut [u8]) -> Result { + fn read_at(&self, _flags: OpenFlags, _offset: usize, _buffer: &mut [u8]) -> Result { Ok(0x00) } - fn write_at(&self, _offset: usize, _buffer: &[u8]) -> Result { - Ok(0x00) + fn write_at(&self, _offset: usize, buffer: &[u8]) -> Result { + Ok(buffer.len()) + } + + fn poll(&self, _table: Option<&mut PollTable>) -> Result { + Ok(PollFlags::OUT) } } @@ -205,7 +214,7 @@ impl Device for DevKmsg { } impl INodeInterface for DevKmsg { - fn read_at(&self, offset: usize, buffer: &mut [u8]) -> Result { + fn read_at(&self, _flags: OpenFlags, offset: usize, buffer: &mut [u8]) -> Result { let buf = logger::get_log_buffer(); let size = core::cmp::min(buffer.len(), buf.len()); @@ -305,7 +314,7 @@ impl INodeInterface for DevFb { count = buffer.len() - ((offset + buffer.len()) - fb.len()); } - let raw = buffer.as_ptr() as *const u32; + let raw = buffer.as_ptr().cast::(); let src = unsafe { core::slice::from_raw_parts(raw, count) }; fb[offset..offset + count].copy_from_slice(src); @@ -331,7 +340,7 @@ impl INodeInterface for DevFb { // This is a shared file mapping. let fb = lock.get_framebuffer(); - let fb_ptr = fb.as_ptr() as *const u8; + let fb_ptr = fb.as_ptr().cast::(); let fb_ptr = fb_ptr.add(offset); let fb_phys_ptr = fb_ptr.sub(crate::PHYSICAL_MEMORY_OFFSET.as_u64() as usize); @@ -352,6 +361,26 @@ impl INodeInterface for DevFb { .expect("/dev/fb: terminal not initialized") } + fn mmap_v2(&self, offset: usize) -> Result { + let rinfo = crate::rendy::get_rendy_info(); + + // Make sure we are in bounds. + if offset > rinfo.byte_len || offset + Size4KiB::SIZE as usize > rinfo.byte_len { + return Err(FileSystemError::NotSupported); + } + + let mut lock = crate::rendy::DEBUG_RENDY.get().unwrap().lock_irq(); + let fb = lock.get_framebuffer(); + + let fb_ptr = fb.as_ptr().cast::(); + let fb_ptr = unsafe { fb_ptr.add(offset) }; + let fb_phys_ptr = unsafe { fb_ptr.sub(crate::PHYSICAL_MEMORY_OFFSET.as_u64() as usize) }; + + Ok(MMapPage::Direct(PhysFrame::containing_address(unsafe { + PhysAddr::new_unchecked(fb_phys_ptr as u64) + }))) + } + fn ioctl(&self, command: usize, arg: usize) -> Result { match command { FBIOGET_VSCREENINFO => { @@ -375,6 +404,19 @@ impl INodeInterface for DevFb { Ok(0x00) } + // Device independent colormap information can be get and set using + // the `FBIOGETCMAP` and `FBIOPUTCMAP` ioctls. + FBIOPUTCMAP => { + let struc = VirtAddr::new(arg as _).read_mut::()?; + log::debug!("fbdev: `FBIOPUTCMAP` is a stub! {struc:?}"); + Ok(0) + } + + FBIOGETCMAP => { + log::warn!("fbdev: `FBIOGETCMAP` is a stub!"); + Ok(0) + } + _ => { log::warn!("fbdev: ioctl unknown command: {command:#x}"); Err(FileSystemError::NotSupported) @@ -406,7 +448,7 @@ impl Device for DevUrandom { } impl INodeInterface for DevUrandom { - fn read_at(&self, _offset: usize, buffer: &mut [u8]) -> Result { + fn read_at(&self, _flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> Result { for (_, b) in buffer.iter_mut().enumerate() { *b = 0; } @@ -430,10 +472,10 @@ pub(super) fn init() -> Result<()> { let rendy_info = crate::rendy::get_rendy_info(); { - let null = DEV_NULL.call_once(|| DevNull::new()); - let kmsg = DEV_KMSG.call_once(|| DevKmsg::new()); + let null = DEV_NULL.call_once(DevNull::new); + let kmsg = DEV_KMSG.call_once(DevKmsg::new); let fb = DEV_FB.call_once(|| DevFb::new(rendy_info)); - let urandom = DEV_URANDOM.call_once(|| DevUrandom::new()); + let urandom = DEV_URANDOM.call_once(DevUrandom::new); install_device(null.clone())?; install_device(kmsg.clone())?; diff --git a/src/aero_kernel/src/fs/epoll.rs b/src/aero_kernel/src/fs/epoll.rs index 8b2dc0d1d1a..8cbf9675c67 100644 --- a/src/aero_kernel/src/fs/epoll.rs +++ b/src/aero_kernel/src/fs/epoll.rs @@ -1,21 +1,22 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +// TODO: The reason why XFE did not run was because of the FXSleep function which uses select() to +// sleep. use aero_syscall::prelude::{EPollEvent, EPollEventFlags}; use aero_syscall::SyscallError; @@ -24,6 +25,7 @@ use alloc::sync::Arc; use hashbrown::HashMap; use crate::userland::scheduler; +use crate::userland::task::TaskState; use crate::utils::sync::Mutex; use super::inode::{INodeInterface, PollTable}; @@ -34,6 +36,14 @@ pub struct EPoll { } impl EPoll { + // FIXME: The bitflags does not support bitwise or operations in const. + const PRIVATE_BITS: EPollEventFlags = EPollEventFlags::from_bits_truncate( + EPollEventFlags::WAKEUP.bits() + | EPollEventFlags::ONESHOT.bits() + | EPollEventFlags::ET.bits() + | EPollEventFlags::EXCLUSIVE.bits(), + ); + pub fn new() -> Arc { Arc::new(Self { events: Mutex::new(HashMap::new()), @@ -86,21 +96,20 @@ impl EPoll { Ok(()) } - /// Retrieves ready events, and delivers them to the caller-supplied event buffer. + /// Retrieves ready events, and delivers them to the caller-supplied event buffer and + /// returns the number of ready events if the call was successful. /// /// ## Arguments /// /// * `events`: Used to return information from the ready list about file descriptors in the - /// interest list that have some events available. + /// interest list that have some events available. /// /// * `max_events`: Maximum number of events. /// - /// * `timeout`: specifies the minimum number of milliseconds that epoll wait will block. Specifying - /// a timeout of `-1` will block indefinitely. While specifing a timeout of `0` will return immediately - /// even if there are available no events. + /// * `timeout`: specifies the minimum number of milliseconds that epoll wait will block. + /// Specifying a timeout of `-1` will block indefinitely. While specifying a timeout of `0` + /// will return immediately even if there are available no events. /// - /// ## Return - /// Returns the number of ready events if the call was successful. /// /// ## Blocking /// Blocks the current task until either: @@ -110,9 +119,9 @@ impl EPoll { /// * The timeout expires. pub fn wait( &self, - ret_events: &mut [&mut EPollEvent], + ret_events: &mut [EPollEvent], max_events: usize, - _timeout: usize, + timeout: usize, ) -> Result { let current_task = scheduler::get_scheduler().current_task(); let file_table = ¤t_task.file_table; @@ -129,6 +138,9 @@ impl EPoll { break; } + ret_events[n].events = EPollEventFlags::empty(); + ret_events[n].data = unsafe { core::mem::zeroed() }; + let fd = file_table .get_handle(*fd) .ok_or(FileSystemError::NotSupported)?; // EINVAL @@ -136,44 +148,84 @@ impl EPoll { let flags = epoll_event.events; let ready: EPollEventFlags = fd.inode().poll(None)?.into(); - if ready.contains(flags) { - // The registered event is ready; increment the number of ready events - // and set event flags mask for this event in the caller-supplied event - // buffer. + // If the event mask does not contain any poll(2) events, the event + // descriptor is disabled. + if flags == Self::PRIVATE_BITS { + continue; + } + + if !(ready & flags).is_empty() { ret_events[n].events = ready & flags; + ret_events[n].data = epoll_event.data; + + if flags.contains(EPollEventFlags::ONESHOT) { + // The `EPOLLONESHOT` bit that disables the descriptor when an event is + // received, until the next `EPOLL_CTL_MOD` will be issued. + epoll_event.events = Self::PRIVATE_BITS; + } + n += 1; continue; } // Not ready; add the event to the poll table. fd.inode().poll(Some(&mut poll_table))?; - fds.push(fd); + fds.push((fd, epoll_event, flags)); } // If all events are ready, we can return now. - if n > 0 { - debug_assert!(fds.len() == 0); + if n > 0 || fds.is_empty() { + debug_assert!(fds.is_empty()); return Ok(n); } + // Start the timer if timeout specified, if not, we can block indefinitely. + // If the timeout is zero, then we have to return without blocking. + if timeout == 0 { + return Ok(0); + } + + if timeout > 0 { + scheduler::get_scheduler().sleep(Some(timeout * 1_000_000))?; + } else { + scheduler::get_scheduler().sleep(None)?; + } + 'search: loop { - // Wait till one of the file descriptor deliever an event. - scheduler::get_scheduler().inner.await_io()?; + if current_task.state() == TaskState::AwaitingIoDeadline + && current_task.load_sleep_duration() == 0 + && timeout > 0 + { + // Timeout has expired. + return Ok(0); + } + + for (fd, event, flags) in fds.iter_mut() { + // If the event mask does not contain any poll(2) events, the event + // descriptor is disabled. + if *flags == Self::PRIVATE_BITS { + continue; + } - for fd in fds.iter() { let ready: EPollEventFlags = fd.inode().poll(None)?.into(); - let flags = table - .get(&fd.fd) - .ok_or(FileSystemError::NotSupported)? - .events; - if ready.contains(flags) { + if !(ready & *flags).is_empty() { // The event is ready; break out of the search loop and set ready // events to 1. - ret_events[0].events = ready & flags; + ret_events[n].events = ready & *flags; + ret_events[n].data = event.data; + + if flags.contains(EPollEventFlags::ONESHOT) { + // The `EPOLLONESHOT` bit that disables the descriptor when an event is + // received, until the next `EPOLL_CTL_MOD` will be issued. + event.events = Self::PRIVATE_BITS; + } + n = 1; break 'search; } + + scheduler::get_scheduler().await_io()?; } } diff --git a/src/aero_kernel/src/fs/eventfd.rs b/src/aero_kernel/src/fs/eventfd.rs index 4de9ffcab22..46b1fdd0abe 100644 --- a/src/aero_kernel/src/fs/eventfd.rs +++ b/src/aero_kernel/src/fs/eventfd.rs @@ -1,70 +1,119 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . +use aero_syscall::OpenFlags; use alloc::sync::Arc; +use spin::Once; +use super::file_table::FileHandle; use super::inode::{INodeInterface, PollFlags, PollTable}; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::fs::FileSystemError; +use crate::utils::sync::{Mutex, WaitQueue}; pub struct EventFd { - wq: BlockQueue, - count: Mutex, + wq: WaitQueue, + /// Every write(2) on an eventfd, the value written is added to `count` and a wakeup + /// is performed on `wq`. + count: Mutex, + // FIXME: https://github.com/Andy-Python-Programmer/aero/issues/113 + handle: Once>, } impl EventFd { pub fn new() -> Arc { Arc::new(Self { - wq: BlockQueue::new(), + wq: WaitQueue::new(), count: Mutex::new(0), + handle: Once::new(), }) } + + fn is_nonblock(&self) -> bool { + let handle = self.handle.get().expect("file handle is not initialized"); + handle.flags().contains(OpenFlags::O_NONBLOCK) + } } impl INodeInterface for EventFd { - fn read_at(&self, _offset: usize, _buffer: &mut [u8]) -> super::Result { - self.wq.notify_complete(); + fn open(&self, handle: Arc) -> super::Result> { + self.handle.call_once(|| handle); + Ok(None) + } + + fn read_at(&self, flags: OpenFlags, _offset: usize, buffer: &mut [u8]) -> super::Result { + let size = core::mem::size_of::(); + assert!(buffer.len() >= size); + + // SAFETY: We have above verified that it is safe to dereference + // the value. + let value = unsafe { &mut *(buffer.as_mut_ptr().cast::()) }; + let mut count = self.wq.wait(flags.into(), &self.count, |e| **e != 0)?; + + *value = *count; + *count = 0; // reset the counter - unimplemented!() + self.wq.notify_all(); + Ok(size) } - fn write_at(&self, _offset: usize, _buffer: &[u8]) -> super::Result { - self.wq.notify_complete(); + fn write_at(&self, _offset: usize, buffer: &[u8]) -> super::Result { + let chunk_size = core::mem::size_of::(); + assert!(buffer.len() >= chunk_size); - unimplemented!() + // TODO: use bytemuck to remove the unsafe. + let target = unsafe { *(buffer.as_ptr().cast::()) }; + + if target == u64::MAX { + return Err(FileSystemError::NotSupported); + } + + let mut count = self.count.lock(); + + if u64::MAX - *count > target { + *count += target; + } else if !self.is_nonblock() { + unimplemented!() + } else { + return Ok(0); + }; + + self.wq.notify_all(); + Ok(chunk_size) } fn poll(&self, table: Option<&mut PollTable>) -> super::Result { - let count = self.count.lock(); + let count = self.count.lock_irq(); let mut events = PollFlags::empty(); - table.map(|e| e.insert(&self.wq)); // listen for changes + if let Some(e) = table { + e.insert(&self.wq) + } if *count > 0 { events.insert(PollFlags::IN); } - if *count == usize::MAX { + if *count == u64::MAX { events.insert(PollFlags::ERR); } - if *count < (usize::MAX - 1) { - events.insert(PollFlags::OUT); // possible to write a value of at least "1" without blocking. + if *count < (u64::MAX - 1) { + events.insert(PollFlags::OUT); // possible to write a value of at least "1" without + // blocking. } Ok(events) diff --git a/src/aero_kernel/src/fs/ext2/disk.rs b/src/aero_kernel/src/fs/ext2/disk.rs new file mode 100644 index 00000000000..615a985ed18 --- /dev/null +++ b/src/aero_kernel/src/fs/ext2/disk.rs @@ -0,0 +1,285 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::time::Duration; + +use bit_field::BitField; + +use crate::fs::inode; +use crate::utils::IncompleteArrayField; + +#[derive(Debug, PartialEq)] +pub enum Revision { + Revision0, + /// Revision 1 introduces variable inode sizes, extended + /// attributes, etc. + Revision1, +} + +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct SuperBlock { + pub inodes_count: u32, + pub blocks_count: u32, + pub r_blocks_count: u32, + pub free_blocks_count: u32, + pub free_inodes_count: u32, + pub first_data_block: u32, + pub log_block_size: u32, + pub log_frag_size: u32, + pub blocks_per_group: u32, + pub frags_per_group: u32, + pub inodes_per_group: u32, + pub mtime: u32, + pub wtime: u32, + pub mnt_count: u16, + pub max_mnt_count: u16, + pub magic: u16, + pub state: u16, + pub errors: u16, + pub minor_rev_level: u16, + pub lastcheck: u32, + pub checkinterval: u32, + pub creator_os: u32, + pub rev_level: u32, + pub def_resuid: u16, + pub def_gid: u16, + + // Extended Superblock fields + // + // XXX: If version number >= 1, we have to use the ext2 extended superblock as well :) + pub first_ino: u32, + pub inode_size: u16, + pub block_group_nr: u16, + pub feature_compat: u32, + pub feature_incompat: u32, + pub feature_ro_compat: u32, + pub uuid: [u64; 2usize], + pub volume_name: [u8; 16usize], + pub last_mounted: [u64; 8usize], + pub compression_info: u32, + pub prealloc_blocks: u8, + pub prealloc_dir_blocks: u8, + pub reserved_gdt_blocks: u16, + pub journal_uuid: [u8; 16usize], + pub journal_inum: u32, + pub journal_dev: u32, + pub last_orphan: u32, + pub hash_seed: [u32; 4usize], + pub def_hash_version: u8, + pub jnl_backup_type: u8, + pub group_desc_size: u16, + pub default_mount_opts: u32, + pub first_meta_bg: u32, + pub mkfs_time: u32, + pub jnl_blocks: [u32; 17usize], +} + +impl SuperBlock { + pub const MAGIC: u16 = 0xef53; + + /// Returns the number of entries per block. + pub fn entries_per_block(&self) -> usize { + self.block_size() / core::mem::size_of::() + } + + pub fn revision(&self) -> Revision { + match self.rev_level { + 0 => Revision::Revision0, + 1 => Revision::Revision1, + revison => unreachable!("ext2: invalid revison {revison}"), + } + } + + /// Returns the size of a block in bytes. + pub fn block_size(&self) -> usize { + 1024usize << self.log_block_size + } + + /// Returns the length of the BGDT. + pub fn bgdt_len(&self) -> usize { + self.blocks_count.div_ceil(self.blocks_per_group) as usize + } + + pub fn bgdt_block(&self) -> usize { + // XXX: The block group descriptors are always located in the block immediately + // following the superblock. + let block_size = self.block_size(); + + if block_size >= 2048 { + block_size + } else { + block_size * 2 + } + } +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct GroupDescriptor { + pub block_bitmap: u32, + pub inode_bitmap: u32, + pub inode_table: u32, + pub free_blocks_count: u16, + pub free_inodes_count: u16, + pub used_dirs_count: u16, + pub pad: u16, + pub reserved: [u8; 12usize], +} + +const_assert_eq!(core::mem::size_of::(), 32); + +#[derive(Debug)] +#[repr(C)] +pub struct DirEntry { + pub inode: u32, + pub entry_size: u16, + pub name_size: u8, + pub file_type: u8, + name: IncompleteArrayField, +} + +impl DirEntry { + pub fn set_name(&mut self, name: &str) { + assert!(name.len() < u8::MAX as usize); + + self.name_size = name.len() as u8; + + let name_bytes = unsafe { self.name.as_mut_slice(name.len()) }; + name_bytes.copy_from_slice(name.as_bytes()); + } + + pub fn name(&self) -> &str { + unsafe { core::str::from_utf8_unchecked(self.name.as_slice(self.name_size as usize)) } + } + + #[inline] + pub fn is_used(&self) -> bool { + // value of 0 indicates that the entry is not used + self.inode != 0 + } +} + +#[repr(u8)] +#[derive(PartialEq, Copy, Clone)] +pub enum FileType { + Unknown = 0, + Fifo = 1, + CharDev = 2, + Directory = 4, + BlockDev = 6, + File = 8, + Symlink = 10, + Socket = 12, +} + +impl FileType { + pub fn bits(&self) -> u16 { + let val = *self as u8; + (val as u16) << 12 + } +} + +impl From for inode::FileType { + fn from(ty: FileType) -> Self { + match ty { + FileType::Symlink => Self::Symlink, + FileType::Directory => Self::Directory, + FileType::BlockDev | FileType::CharDev => Self::Device, + + _ => Self::File, + } + } +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct INode { + type_and_perm: u16, + pub user_id: u16, + size_lower: u32, + last_access: u32, + pub creation_time: u32, + last_modification: u32, + pub deletion_time: u32, + pub group_id: u16, + pub hl_count: u16, + pub block_count: u32, + pub flags: u32, + pub os_specific: u32, + pub data_ptr: [u32; 15], + pub gen_number: u32, + pub ext_attr_block: u32, + pub size_or_acl: u32, + pub fragment_address: u32, + pub os_specific2: [u8; 12], +} + +impl INode { + pub fn set_file_type(&mut self, file_type: FileType) { + // The last 4 bits are used to store the filetype. + let mask = 0b0000_1111_1111_1111u16; + self.type_and_perm = file_type.bits() | (self.type_and_perm & mask); + } + + pub fn set_size(&mut self, size: usize) { + self.size_lower = size as u32; + self.size_or_acl = (size >> 32) as u32; + } + + pub fn size(&self) -> usize { + self.size_lower as usize | ((self.size_or_acl as usize) << 32) + } + + pub fn set_permissions(&mut self, permissions: u16) { + let mut val = self.type_and_perm; + val.set_bits(..13, permissions); + self.type_and_perm = val; + } + + pub fn file_type(&self) -> FileType { + let ty = self.type_and_perm >> 12; + + match ty { + 0x1 => FileType::Fifo, + 0x2 => FileType::CharDev, + 0x4 => FileType::Directory, + 0x6 => FileType::BlockDev, + 0x8 => FileType::File, + 0xa => FileType::Symlink, + 0xc => FileType::Socket, + _ => FileType::Unknown, + } + } + + #[inline] + pub fn last_access(&self) -> Duration { + Duration::from_secs(self.last_access as u64) + } + + #[inline] + pub fn last_modification(&self) -> Duration { + Duration::from_secs(self.last_modification as u64) + } + + #[inline] + pub fn creation_time(&self) -> Duration { + Duration::from_secs(self.creation_time as u64) + } +} + +const_assert_eq!(core::mem::size_of::(), 128); diff --git a/src/aero_kernel/src/fs/ext2/group_desc.rs b/src/aero_kernel/src/fs/ext2/group_desc.rs new file mode 100644 index 00000000000..af3578d735d --- /dev/null +++ b/src/aero_kernel/src/fs/ext2/group_desc.rs @@ -0,0 +1,229 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use alloc::boxed::Box; +use alloc::sync::{Arc, Weak}; + +use bit_field::BitField; +use spin::RwLock; + +use crate::fs::block::{BlockDevice, CachedAccess}; + +use super::{disk, Ext2}; + +pub struct GroupDescriptors { + descriptors: RwLock>, + ext2: Weak, +} + +impl GroupDescriptors { + /// Reads the block group descriptors from the disk. + /// + /// ## Arguments + /// + /// * `ext2` - Weak pointer to the EXT2 filesystem. This function does not call `upgrade` on the + /// pointer so, it is valid to pass a semi-constructed `Arc` pointer (e.g through + /// `Arc::new_cyclic`) though invoking other functions on the group descriptors require the + /// pointer to be fully constructed). + /// + /// * `superblock` - Reference to the EXT2 superblock. + /// + /// * `device` - Block device to read the group descriptors from. + pub fn new( + ext2: Weak, + device: &BlockDevice, + superblock: &disk::SuperBlock, + ) -> Option { + let bgdt_len = superblock.bgdt_len(); + let mut bgdt = Box::<[disk::GroupDescriptor]>::new_uninit_slice(bgdt_len); + + device.read(superblock.bgdt_block(), bgdt.as_bytes_mut())?; + + // SAFETY: We have initialized the BGD (Block Group Descriptor Table) above. + let bgdt = unsafe { bgdt.assume_init() }; + Some(Self { + descriptors: RwLock::new(bgdt), + ext2, + }) + } + + // XXX: The free inodes are managed by bitmaps. An EXT2 filesystem contains + // several block groups where each group contains a bitmap for blocks and + // a bitmap for inodes and their free counts. The group descriptors are located + // after the super block. + + /// Returns the index of the block group which has free block(s) + /// available. + pub fn find_free_block(&self) -> Option { + let (index, _) = self + .descriptors + .read() + .iter() + .enumerate() + .find(|(_, e)| e.free_blocks_count >= 1)?; + + Some(index) + } + + /// Returns the index of the block group which has free inode(s) + /// available. + pub fn find_free_inode(&self) -> Option { + let (index, _) = self + .descriptors + .read() + .iter() + .enumerate() + .find(|(_, e)| e.free_inodes_count >= 1)?; + + Some(index) + } + + pub fn find_inode(&self, id: usize) -> Option> { + let fs = self.ext2.upgrade()?; + let this = self.descriptors.read(); + let superblock = &fs.superblock; + + // There is one inode table per block group and can be located by + // the `inode_table` offset in the group descriptor. Also there are + // `inodes_per_group` inodes per table. + let ino_per_group = superblock.inodes_per_group as usize; + + let ino_block_group = (id - 1) / ino_per_group; + let ino_table_index = (id - 1) % ino_per_group; + + let group_descriptor = this[ino_block_group]; + let table_offset = group_descriptor.inode_table as usize * superblock.block_size(); + + let mut inode = Box::::new_uninit(); + + fs.block.read( + table_offset + (ino_table_index * core::mem::size_of::()), + inode.as_bytes_mut(), + )?; + + // SAFETY: We have initialized the inode above. + let inode = unsafe { inode.assume_init() }; + Some(inode) + } + + /// Allocates a block pointer using the first fit allocation strategy. + pub fn alloc_block_ptr(&self) -> Option { + let fs = self.ext2.upgrade()?; + let blocks_per_group = fs.superblock.blocks_per_group as usize; + + if let Some(block_group_idx) = self.find_free_block() { + let mut descriptors = self.descriptors.write(); + let block_group = &mut descriptors[block_group_idx]; + + let mut bitmap = Bitmap::new(&fs, block_group.block_bitmap as usize)?; + let block_id = block_group_idx * blocks_per_group + bitmap.alloc()?; + + block_group.free_blocks_count -= 1; + drop(descriptors); + + // TODO: decrement the number of free blocks in the superblock. + return Some(block_id); + } + + None + } + + /// Allocates a new inode using the first fit allocation strategy. + pub fn alloc_inode(&self) -> Option { + let fs = self.ext2.upgrade()?; + let ino_per_group = fs.superblock.inodes_per_group as usize; + + if let Some(block_group_idx) = self.find_free_inode() { + let mut descriptors = self.descriptors.write(); + let block_group = &mut descriptors[block_group_idx]; + + let mut bitmap = Bitmap::new(&fs, block_group.inode_bitmap as usize)?; + // Since inode numbers start from 1 rather than 0, the first bit in the first block + // group's inode bitmap represent inode number 1. Thus, we add 1 to the allocated + // inode number. + let inode_id = block_group_idx * ino_per_group + bitmap.alloc()? + 1; + + block_group.free_inodes_count -= 1; + drop(descriptors); // release the lock + + return Some(inode_id); + } + + None + } +} + +struct Bitmap { + bitmap: Box<[u8]>, + fs: Weak, + offset: usize, +} + +impl Bitmap { + /// Reads the bitmap at `block` from the disk. The bitmap is required have + /// a size of `block_size` bytes. + /// + /// **Note**: Any changes to the bitmap will be written back to the disk when the + /// bitmap has been dropped. + fn new(fs: &Arc, block: usize) -> Option { + let block_size = fs.superblock.block_size(); + let offset = block * block_size; + + let mut bitmap = Box::<[u8]>::new_uninit_slice(block_size); + + fs.block.read(offset, &mut bitmap)?; + + // SAFETY: We have initialized the bitmap above. + let bitmap = unsafe { bitmap.assume_init() }; + + Some(Self { + bitmap, + offset, + fs: Arc::downgrade(fs), + }) + } + + /// Allocates a free bit in the bitmap and returns its index. + pub fn alloc(&mut self) -> Option { + for (i, byte) in self.bitmap.iter_mut().enumerate() { + if *byte == u8::MAX { + continue; + } + + for bit in 0..8 { + if !byte.get_bit(bit) { + byte.set_bit(bit, true); + + return Some(i * 8 + bit); + } + } + } + + None + } +} + +impl Drop for Bitmap { + fn drop(&mut self) { + let fs = self + .fs + .upgrade() + .expect("ext2: filesystem has been dropped"); + + fs.block.write(self.offset, &self.bitmap); + } +} diff --git a/src/aero_kernel/src/fs/ext2/mod.rs b/src/aero_kernel/src/fs/ext2/mod.rs new file mode 100644 index 00000000000..e4f5fa17f1d --- /dev/null +++ b/src/aero_kernel/src/fs/ext2/mod.rs @@ -0,0 +1,805 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +mod disk; +mod group_desc; + +use core::mem::MaybeUninit; + +use aero_syscall::socket::{MessageFlags, MessageHeader}; +use aero_syscall::{MMapFlags, OpenFlags, SyscallError}; +use alloc::boxed::Box; +use alloc::string::ToString; +use alloc::sync::{Arc, Weak}; +use spin::RwLock; + +use crate::fs::block::{BlockDeviceInterface, DirtyRef}; +use crate::fs::cache::CachedINode; +use crate::fs::ext2::disk::{FileType, Revision, SuperBlock}; +use crate::mem::paging::*; + +use crate::socket::unix::UnixSocket; +use crate::socket::SocketAddrRef; + +use self::group_desc::GroupDescriptors; + +use super::block::{self, BlockDevice, CachedAccess, PAGE_CACHE}; + +use super::cache::{DirCacheItem, INodeCacheItem}; +use super::path::PathBuf; +use super::{cache, FileSystemError, Path}; + +use super::inode::{self, INodeInterface, MMapPage, Metadata, PollFlags, PollTable}; +use super::FileSystem; + +pub struct INode { + id: usize, + fs: Weak, + inode: RwLock>, + // Forwards all of the inode operations to the proxy inode. Note that the + // proxy inode is not saved on the disk. (e.g. This is useful for binding + // a socket inode to a file). + proxy: Option>, + + // TODO: Do not store this in the inode, but rather in a different + // cache using the API provided by fs::cache (consider LRU only?). + sref: Weak, +} + +impl INode { + pub fn new( + ext2: Weak, + id: usize, + proxy: Option>, + ) -> Option { + debug_assert!(id != 0); + + let icache = cache::icache(); + + // Check if the inode is in the cache. + if let Some(inode) = icache.get(INodeCacheItem::make_key(ext2.clone(), id)) { + Some(inode) + } else { + let fs = ext2.upgrade()?; + let inode = fs.bgdt.find_inode(id)?; + + Some( + icache.make_item_cached(CachedINode::new(Arc::new_cyclic(|sref| Self { + inode: RwLock::new(inode), + id, + fs: ext2, + proxy, + + sref: sref.clone(), + }))), + ) + } + } + + /// Reads the data at `offset` as `T`. + /// + /// ## Safety + /// * The data being read should be of a valid value for `T`. + pub unsafe fn read_mut(&self, offset: usize) -> block::DirtyRef { + assert!(core::mem::size_of::() <= Size4KiB::SIZE as usize); + + let filesystem = self.fs.upgrade().unwrap(); + let block_size = filesystem.superblock.block_size(); + + let block = offset / block_size; + let loc = offset % block_size; + + let block_index = self.get_block(block).unwrap() as usize; + + block::DirtyRef::new(&filesystem.block.sref(), (block_index * block_size) + loc) + } + + pub fn read(&self, offset: usize, buffer: &mut [MaybeUninit]) -> super::Result { + let inode = self.inode.read(); + let filesystem = self.fs.upgrade().unwrap(); + let block_size = filesystem.superblock.block_size(); + + let mut progress = 0; + let count = core::cmp::min(inode.size() - offset, buffer.len()); + + while progress < count { + let block = (offset + progress) / block_size; + let loc = (offset + progress) % block_size; + + let mut chunk = count - progress; + + if chunk > block_size - loc { + chunk = block_size - loc; + } + + let block_index = self.get_block(block).unwrap() as usize; + + filesystem + .block + .read( + (block_index * block_size) + loc, + &mut buffer[progress..progress + chunk], + ) + .expect("inode: read failed"); + + progress += chunk; + } + + Ok(count) + } + + pub fn write(&self, offset: usize, buffer: &[u8]) -> super::Result { + let filesystem = self.fs.upgrade().unwrap(); + let block_size = filesystem.superblock.block_size(); + + let mut progress = 0; + let count = buffer.len(); + + let size = self.inode.read().size(); + while progress < count { + let block = (offset + progress) / block_size; + let loc = (offset + progress) % block_size; + + let mut chunk = count - progress; + + if chunk > block_size - loc { + chunk = block_size - loc; + } + + let mut block_index = self.get_block(block).unwrap() as usize; + + if block_index == 0 { + block_index = self.append_block().unwrap(); + } + + filesystem + .block + .write( + (block_index * block_size) + loc, + &buffer[progress..progress + chunk], + ) + .expect("inode: write failed"); + + progress += chunk; + } + self.inode.write().set_size(offset + count); + + Ok(count) + } + + pub fn append_block(&self) -> Option { + let fs = self.fs.upgrade().expect("ext2: filesystem was dropped"); + let block_size = fs.superblock.block_size(); + let entries_per_block = fs.superblock.entries_per_block(); + + let new_block = fs.bgdt.alloc_block_ptr()?; + + let mut next_block_num = self.inode.read().size().div_ceil(block_size); + + if next_block_num < 12 { + let mut inode = self.inode.write(); + + assert_eq!(inode.data_ptr[next_block_num], 0); + + inode.data_ptr[next_block_num] = new_block as u32; + + let size = inode.size() + block_size; + inode.set_size(size); + + return Some(new_block); + } + + // indirect block + next_block_num -= 12; + + if next_block_num >= entries_per_block { + unimplemented!("append_block: doubly and triply indirect") + } else { + // singly indirect block + let mut block_ptrs = self.inode.read().data_ptr[12] as usize; + + if block_ptrs == 0 { + block_ptrs = fs.bgdt.alloc_block_ptr()?; + self.inode.write().data_ptr[12] = block_ptrs as u32; + } + + let block_ptrs = block_ptrs * block_size; + let offset = block_ptrs + (next_block_num * core::mem::size_of::()); + + fs.block.write(offset, &new_block.to_le_bytes()); + + let mut inode = self.inode.write(); + let inode_size = inode.size() + block_size; + inode.set_size(inode_size); + } + + Some(new_block) + } + + pub fn get_block(&self, mut block: usize) -> Option { + // There are pointers to the first 12 blocks which contain the file's + // data in the inode. There is a pointer to an indirect block (which + // contains pointers to the next set of blocks), a pointer to a doubly + // indirect block and a pointer to a triply indirect block. + if block < 12 { + // direct block + return Some(self.inode.read().data_ptr[block]); + } + + // indirect block + block -= 12; + + let fs = self.fs.upgrade()?; + let superblock = &fs.superblock; + + let entries_per_block = superblock.entries_per_block(); + let block_size = superblock.block_size(); + + if block >= entries_per_block { + // doubly indirect block + block -= entries_per_block; + + let index = block / entries_per_block; + let mut indirect_block = MaybeUninit::::uninit(); + + if index >= entries_per_block { + // treply indirect block + todo!() + } else { + let block_ptrs = self.inode.read().data_ptr[13] as usize * block_size; + let offset = block_ptrs + (index * core::mem::size_of::()); + + fs.block + .read(offset, indirect_block.as_bytes_mut()) + .unwrap(); + } + + // SAFETY: We have initialized the variable above. + let indirect_block = unsafe { indirect_block.assume_init() } as usize * block_size; + let offset = indirect_block + (block % entries_per_block) * core::mem::size_of::(); + + let mut res = MaybeUninit::::uninit(); + fs.block.read(offset, res.as_bytes_mut()); + + // SAFETY: We have initialized the variable above. + Some(unsafe { res.assume_init() }) + } else { + // singly indirect block + let block_ptrs = self.inode.read().data_ptr[12] as usize * block_size; + let offset = block_ptrs + (block * core::mem::size_of::()); + + let mut res = MaybeUninit::::uninit(); + fs.block.read(offset, res.as_bytes_mut()); + + // SAFETY: We have initialized the variable above. + Some(unsafe { res.assume_init() }) + } + } + + pub fn make_disk_dirent(&self, inode: &INode, file_type: u8, name: &str) { + // TODO: scan for unused directory entries and check if this can be + // inserted into the existing block. + let block = self.append_block().unwrap(); + let fs = self.fs.upgrade().expect("ext2: filesystem was dropped"); + let block_size = fs.superblock.block_size(); + + let mut entry = DirtyRef::::new(&fs.block.sref(), block * block_size); + entry.entry_size = block_size as _; + entry.inode = inode.id as _; + entry.file_type = file_type; + // JSDJFKDSJFHJK CHECK THIS this is ub + entry.set_name(name); + } + + pub fn make_inode( + &self, + name: &str, + typ: FileType, + proxy: Option>, + ) -> super::Result { + if !self.metadata()?.is_directory() { + return Err(FileSystemError::NotDirectory); + } + + if DirEntryIter::new(self.sref()).any(|entry| entry.name() == name) { + return Err(FileSystemError::EntryExists); + } + + assert!(self.inode.read().hl_count != 0, "ext2: dangling inode"); + + let fs = self.fs.upgrade().expect("ext2: filesystem was dropped"); + + let inode = fs.bgdt.alloc_inode().expect("ext2: out of inodes"); + let inode = fs.find_inode(inode, proxy).expect("ext2: inode not found"); + + let ext2_inode = inode.downcast_arc::().expect("ext2: invalid inode"); + + { + let mut inode = ext2_inode.inode.write(); + **inode = disk::INode::default(); + + inode.set_file_type(typ); + inode.set_permissions(0o755); + + inode.hl_count += 1; + } + + // FIXME: Fix the filetype! + self.make_disk_dirent(&ext2_inode, 2, name); + Ok(inode) + } + + pub fn make_dirent( + &self, + parent: DirCacheItem, + name: &str, + entry: &disk::DirEntry, + ) -> Option { + let inode = self.fs.upgrade()?.find_inode(entry.inode as usize, None)?; + Some(inode::DirEntry::new(parent, inode, name.to_string())) + } + + pub fn sref(&self) -> Arc { + self.sref.upgrade().unwrap() + } +} + +impl CachedAccess for INode { + fn sref(&self) -> Weak { + self.sref.clone() + } + + fn read_direct(&self, offset: usize, dest: PhysFrame) -> Option { + INodeInterface::read_at(self, OpenFlags::empty(), offset, dest.as_slice_mut()).ok() + } + + fn write_direct(&self, offset: usize, src: PhysFrame) -> Option { + INodeInterface::write_at(self, offset, src.as_slice_mut()).ok() + } +} + +impl INodeInterface for INode { + fn weak_filesystem(&self) -> Option> { + Some(self.fs.clone()) + } + + fn metadata(&self) -> super::Result { + let inode = self.inode.read(); + + Ok(Metadata { + id: self.id, + file_type: inode.file_type().into(), + size: inode.size(), + children_len: 0, + }) + } + + fn stat(&self) -> super::Result { + use super::inode::FileType; + use aero_syscall::{Mode, Stat}; + + let inode = self.inode.read(); + + let filesystem = self.fs.upgrade().unwrap(); + let filetype = inode.file_type().into(); + + let mut mode = Mode::empty(); + + match filetype { + FileType::File => mode.insert(Mode::S_IFREG), + FileType::Directory => mode.insert(Mode::S_IFDIR), + FileType::Device => mode.insert(Mode::S_IFCHR), + FileType::Socket => mode.insert(Mode::S_IFSOCK), + FileType::Symlink => mode.insert(Mode::S_IFLNK), + } + + // FIXME: read permission bits from the inode. + mode.insert(Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO); + + Ok(Stat { + st_ino: self.id as _, + st_blksize: filesystem.superblock.block_size() as _, + st_size: inode.size() as _, + st_mode: mode, + + st_atim: inode.last_access().into(), + st_mtim: inode.last_modification().into(), + st_ctim: inode.creation_time().into(), + + ..Default::default() + }) + } + + fn dirent(&self, parent: DirCacheItem, index: usize) -> super::Result> { + if let Some(entry) = DirEntryIter::new(self.sref()).nth(index) { + Ok(self.make_dirent(parent, entry.name(), entry)) + } else { + Ok(None) + } + } + + fn lookup(&self, parent: DirCacheItem, name: &str) -> super::Result { + let entry = DirEntryIter::new(self.sref()) + .find(|entry| entry.name() == name) + .ok_or(FileSystemError::EntryNotFound)?; + + Ok(self.make_dirent(parent, entry.name(), entry).unwrap()) + } + + fn read_at( + &self, + flags: OpenFlags, + offset: usize, + usr_buffer: &mut [u8], + ) -> super::Result { + if let Some(proxy) = self.proxy.as_ref() { + return proxy.read_at(flags, offset, usr_buffer); + } + + if !self.metadata()?.is_file() { + return Err(FileSystemError::NotSupported); + } + + let buffer = unsafe { + core::slice::from_raw_parts_mut(usr_buffer.as_mut_ptr().cast(), usr_buffer.len()) + }; + + self.read(offset, buffer) + } + + fn write_at(&self, offset: usize, usr_buffer: &[u8]) -> super::Result { + if let Some(proxy) = self.proxy.as_ref() { + return proxy.write_at(offset, usr_buffer); + } + + if !self.metadata()?.is_file() && !self.metadata()?.is_symlink() { + return Err(FileSystemError::NotSupported); + } + + self.write(offset, usr_buffer) + } + + fn rename(&self, old: DirCacheItem, dest: &str) -> super::Result<()> { + assert!(self.metadata()?.is_directory()); + + if DirEntryIter::new(self.sref()).any(|entry| entry.name() == dest) { + return Err(FileSystemError::EntryExists); + } + + if let Some(_parent) = old.parent() { + // FIXME: Remove the directory entry from the parent + self.make_disk_dirent(&old.inode().downcast_arc().unwrap(), 2, dest); + return Ok(()); + } + + Err(FileSystemError::NotSupported) + } + + fn link(&self, name: &str, src: DirCacheItem) -> super::Result<()> { + if !self.metadata()?.is_directory() { + return Err(FileSystemError::NotSupported); + } + + if src.inode().metadata()?.is_directory() { + return Err(FileSystemError::NotSupported); + } + + let inode = self.make_inode(name, FileType::Symlink, None)?; + inode.write_at(0, src.name().as_bytes())?; + + Ok(()) + } + + fn truncate(&self, size: usize) -> super::Result<()> { + let inode = self.inode.read(); + + if inode.size() > size { + // grow inode + log::warn!("ext2::truncate(at=grow) is a stub!"); + } else if inode.size() < size { + log::warn!("ext2::truncate(at=shrink) is a stub!"); + // shrink inode + } + + Ok(()) + } + + fn touch(&self, parent: DirCacheItem, name: &str) -> super::Result { + if !self.metadata()?.is_directory() { + return Err(FileSystemError::NotDirectory); + } + + let inode = self.make_inode(name, FileType::File, None)?; + Ok(inode::DirEntry::new(parent, inode, name.to_string())) + } + + fn mkdir(&self, name: &str) -> super::Result { + if !self.metadata()?.is_directory() { + return Err(FileSystemError::NotDirectory); + } + + self.make_inode(name, FileType::Directory, None) + } + + fn make_local_socket_inode( + &self, + name: &str, + inode: Arc, + ) -> super::Result { + self.make_inode(name, FileType::Socket, Some(inode)) + } + + fn resolve_link(&self) -> super::Result { + if !self.metadata()?.is_symlink() { + return Err(FileSystemError::NotSupported); + } + + let inode = self.inode.read(); + + let path_len = inode.size(); + let data_bytes: &[u8] = bytemuck::cast_slice(&inode.data_ptr); + + // XXX: Symlinks under 60 bytes store data within the inode to avoid allocating a full + // block. + if path_len <= data_bytes.len() { + let path_bytes = &data_bytes[..path_len]; + let path = core::str::from_utf8(path_bytes).or(Err(FileSystemError::InvalidPath))?; + + Ok(path.into()) + } else { + let mut buffer = Box::<[u8]>::new_uninit_slice(path_len); + self.read(0, buffer.as_bytes_mut())?; + + let path_bytes = unsafe { buffer.assume_init() }; + let path = core::str::from_utf8(&path_bytes).or(Err(FileSystemError::InvalidPath))?; + + Ok(path.into()) + } + } + + fn symlink(&self, target: &Path) -> super::Result<()> { + let mut inode = self.inode.write(); + inode.set_file_type(FileType::Symlink); + + let target_len = target.len(); + let data_bytes: &mut [u8] = bytemuck::cast_slice_mut(&mut inode.data_ptr); + + // XXX: Symlinks under 60 bytes store data within the inode to avoid allocating a full + // block. + if target_len <= data_bytes.len() { + data_bytes[..target_len].copy_from_slice(target.as_bytes()); + inode.set_size(target_len); + } else { + drop(inode); + assert_eq!(self.write(0, target.as_bytes())?, target_len); + } + + Ok(()) + } + + fn mmap(&self, offset: usize, size: usize, flags: MMapFlags) -> super::Result { + assert!(self.proxy.is_none()); + + // TODO: support shared file mappings. + // assert!(!flags.contains(MMapFlags::MAP_SHARED)); + + let private_cp: PhysFrame = FRAME_ALLOCATOR.allocate_frame().unwrap(); + private_cp.as_slice_mut().fill(0); + + let buffer = &mut private_cp.as_slice_mut()[..size]; + self.read_at(OpenFlags::empty(), offset, buffer)?; + + Ok(private_cp) + } + + // TODO: cleanup + fn mmap_v2(&self, offset: usize) -> super::Result { + Ok(MMapPage::PageCache(PAGE_CACHE.get_page( + &(self.sref.clone() as Weak), + offset, + ))) + } + + fn listen(&self, backlog: usize) -> Result<(), SyscallError> { + if let Some(proxy) = self.proxy.as_ref() { + return proxy.listen(backlog); + } + + Err(SyscallError::EACCES) + } + + // XXX: We do not require to handle `bind` here since if this function + // is being is called on an EXT2 inode then, it has already been bound. + + fn connect(&self, address: SocketAddrRef, length: usize) -> super::Result<()> { + if let Some(proxy) = self.proxy.as_ref() { + return proxy.connect(address, length); + } + + Err(FileSystemError::NotSupported) + } + + fn accept(&self, address: Option<(VirtAddr, &mut u32)>) -> super::Result> { + if let Some(proxy) = self.proxy.as_ref() { + return proxy.accept(address); + } + + Err(FileSystemError::NotSupported) + } + + fn send(&self, message_hdr: &mut MessageHeader, flags: MessageFlags) -> super::Result { + if let Some(proxy) = self.proxy.as_ref() { + proxy.send(message_hdr, flags) + } else { + Err(FileSystemError::NotSupported) + } + } + + fn recv( + &self, + fd_flags: OpenFlags, + message_hdr: &mut MessageHeader, + flags: MessageFlags, + ) -> super::Result { + if let Some(proxy) = self.proxy.as_ref() { + proxy.recv(fd_flags, message_hdr, flags) + } else { + Err(FileSystemError::NotSupported) + } + } + + fn poll(&self, table: Option<&mut PollTable>) -> super::Result { + if let Some(proxy) = self.proxy.as_ref() { + return proxy.poll(table); + } + + Err(FileSystemError::NotSupported) + } + + fn as_unix_socket(&self) -> super::Result> { + self.proxy + .as_ref() + .ok_or(FileSystemError::NotSocket) + .cloned() + } +} + +pub struct DirEntryIter<'a> { + inode: Arc, + offset: usize, + + current_block: Box<[MaybeUninit]>, + block_size: usize, + _phantom: core::marker::PhantomData<&'a disk::DirEntry>, +} + +impl<'a> DirEntryIter<'a> { + pub fn new(inode: Arc) -> Self { + let block_size = inode.fs.upgrade().unwrap().superblock.block_size(); + let buf = Box::<[u8]>::new_uninit_slice(block_size); + + Self { + inode, + offset: 0, + current_block: buf, + block_size, + + _phantom: core::marker::PhantomData, + } + } +} + +impl<'a> Iterator for DirEntryIter<'a> { + type Item = &'a mut disk::DirEntry; + + fn next(&mut self) -> Option { + // Read 1 block at a time. + // + // XXX: A directory entry cannot span between multiple data blocks. + let file_size = self.inode.inode.read().size(); + + if self.offset + core::mem::size_of::() > file_size { + return None; + } + + let block_offset = self.offset % self.block_size; + if block_offset == 0 { + self.inode + .read(self.offset, &mut self.current_block) + .unwrap(); + } + + // SAFETY: We have initialized the current block above. + let entry = unsafe { + &mut *self + .current_block + .as_mut_ptr() + .add(block_offset) + .cast::() + }; + + if !entry.is_used() { + return None; + } + + self.offset += entry.entry_size as usize; + Some(entry) + } +} + +pub struct Ext2 { + superblock: Box, + bgdt: GroupDescriptors, + block: Arc, + + sref: Weak, +} + +impl Ext2 { + const ROOT_INODE_ID: usize = 2; + + pub fn new(block: Arc) -> Option> { + let mut superblock = Box::::new_uninit(); + block.read_block(2, superblock.as_bytes_mut())?; + + // SAFETY: We have initialized the superblock above. + let superblock = unsafe { superblock.assume_init() }; + + if superblock.magic != SuperBlock::MAGIC { + return None; + } + + log::trace!( + "ext2: initialized (block_size={}, entries_per_block={})", + superblock.block_size(), + superblock.entries_per_block(), + ); + + assert_eq!(superblock.revision(), Revision::Revision1); + assert_eq!( + superblock.inode_size as usize, + core::mem::size_of::() + ); + + Some(Arc::new_cyclic(|sref| Self { + bgdt: GroupDescriptors::new(sref.clone(), &block, &superblock) + .expect("ext2: failed to read group descriptors"), + superblock, + block, + + sref: sref.clone(), + })) + } + + pub fn find_inode( + &self, + id: usize, + proxy: Option>, + ) -> Option { + INode::new(self.sref.clone(), id, proxy) + } +} + +impl FileSystem for Ext2 { + fn root_dir(&self) -> DirCacheItem { + let inode = self + .find_inode(Ext2::ROOT_INODE_ID, None) + .expect("ext2: invalid filesystem (root inode not found)"); + + inode::DirEntry::new_root(inode, String::from("/")) + } +} diff --git a/src/aero_kernel/src/fs/file_table.rs b/src/aero_kernel/src/fs/file_table.rs index b47237d531e..d8d0c84f9f1 100644 --- a/src/aero_kernel/src/fs/file_table.rs +++ b/src/aero_kernel/src/fs/file_table.rs @@ -1,31 +1,28 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::sync::atomic::{AtomicUsize, Ordering}; -use aero_syscall::prelude::FdFlags; use aero_syscall::{OpenFlags, SysDirEntry}; use alloc::sync::Arc; use alloc::vec::Vec; -use spin::{Mutex, RwLock}; +use spin::RwLock; use crate::fs::cache::DirCacheImpl; @@ -33,6 +30,7 @@ use super::cache::{DirCacheItem, INodeCacheItem}; use super::inode::FileType; use super::FileSystemError; +#[derive(Debug, Copy, Clone)] pub enum DuplicateHint { Exact(usize), Any, @@ -45,8 +43,7 @@ pub struct FileHandle { // We need to store the `offset` behind an Arc since when the file handle // is duplicated, the `offset` needs to be in sync with the parent. pub offset: Arc, - pub flags: OpenFlags, - pub fd_flags: Mutex, + flags: RwLock, } impl FileHandle { @@ -54,19 +51,47 @@ impl FileHandle { pub fn new(fd: usize, inode: DirCacheItem, flags: OpenFlags) -> Self { Self { fd, - inode: inode.clone(), + inode, offset: Arc::new(AtomicUsize::new(0)), - flags, - fd_flags: Mutex::new(FdFlags::empty()), + flags: RwLock::new(flags), } } + #[inline] + pub fn is_writable(&self) -> bool { + self.flags() + .intersects(OpenFlags::O_WRONLY | OpenFlags::O_RDWR) + } + + #[inline] + pub fn is_readable(&self) -> bool { + // FIXME: switch to Linux ABI for fcntl. mlibc defines O_RDONLY as 0 so, we have to infer + // the read-only flag. + let flags = self.flags(); + flags.contains(OpenFlags::O_RDWR) || !flags.contains(OpenFlags::O_WRONLY) + } + + pub fn flags(&self) -> OpenFlags { + *self.flags.read() + } + + pub fn set_flags(&self, flags: OpenFlags) { + *self.flags.write() = flags; + } + pub fn read(&self, buffer: &mut [u8]) -> super::Result { let offset = self.offset.load(Ordering::SeqCst); - let new_offset = self.inode.inode().read_at(offset, buffer)?; + let new_offset = self.inode.inode().read_at(self.flags(), offset, buffer)?; self.offset.fetch_add(new_offset, Ordering::SeqCst); + Ok(new_offset) + } + + pub fn write(&self, buffer: &[u8]) -> super::Result { + let offset = self.offset.load(Ordering::SeqCst); + let new_offset = self.inode.inode().write_at(offset, buffer)?; + self.offset.fetch_add(new_offset, Ordering::SeqCst); Ok(new_offset) } @@ -105,15 +130,6 @@ impl FileHandle { } } - pub fn write(&self, buffer: &[u8]) -> super::Result { - let offset = self.offset.load(Ordering::SeqCst); - let new_offset = self.inode.inode().write_at(offset, buffer)?; - - self.offset.fetch_add(new_offset, Ordering::SeqCst); - - Ok(new_offset) - } - pub fn dirnode(&self) -> DirCacheItem { self.inode.clone() } @@ -123,16 +139,15 @@ impl FileHandle { } pub fn duplicate(&self, dupfd: usize, flags: OpenFlags) -> super::Result> { - let flags = self.flags | flags; + let flags = *self.flags.read() | flags; let new = Arc::new(Self { fd: dupfd, inode: self.inode.clone(), offset: self.offset.clone(), - flags, - fd_flags: Mutex::new(self.fd_flags.lock().clone()), + flags: RwLock::new(flags), }); - new.inode.inode().open(flags)?; + new.inode.inode().open(new.clone())?; Ok(new) } @@ -161,7 +176,7 @@ impl FileHandle { let file_type = entry.inode().metadata()?.file_type(); let file_type: aero_syscall::SysFileType = file_type.into(); - let sysd = unsafe { &mut *(buffer.as_mut_ptr() as *mut SysDirEntry) }; + let sysd = unsafe { &mut *(buffer.as_mut_ptr().cast::()) }; sysd.inode = entry.inode().metadata()?.id(); sysd.offset = reclen; @@ -178,14 +193,14 @@ impl FileHandle { self.offset.fetch_add(1, Ordering::SeqCst); Ok(reclen) } else { - // nothin to read + // nothing to read Ok(0) } } } #[repr(transparent)] -pub struct FileTable(RwLock>>>); +pub struct FileTable(pub RwLock>>>); impl FileTable { pub fn new() -> Self { @@ -198,10 +213,8 @@ impl FileTable { pub fn get_handle(&self, fd: usize) -> Option> { let files = self.0.read(); - if let Some(file) = &files.get(fd) { - if let Some(handle) = file { - return Some(handle.clone()); - } + if let Some(Some(handle)) = &files.get(fd) { + return Some(handle.clone()); } None @@ -210,13 +223,26 @@ impl FileTable { pub fn log(&self) { let files = self.0.read(); - for handle in files.iter() { - if let Some(handle) = handle { - log::debug!( - "file handle: (fd={}, path=`{}`)", - handle.fd, - handle.inode.absolute_path_str() - ) + for handle in files.iter().flatten() { + log::debug!( + "file handle: (fd={}, path=`{}`)", + handle.fd, + handle.inode.absolute_path() + ) + } + } + + pub fn close_on_exec(&self) { + let mut files = self.0.write(); + + for file in files.iter_mut() { + if let Some(handle) = file { + let flags = *handle.flags.read(); + + if flags.contains(OpenFlags::O_CLOEXEC) { + handle.inode().close(flags); + *file = None; + } } } } @@ -238,11 +264,11 @@ impl FileTable { let array = &mut files[start..]; // Loop over the current file descriptor table and find the first - // avaliable file descriptor. + // available file descriptor. for (i, file) in array.iter_mut().enumerate() { if file.is_none() { *file = Some(handle.duplicate(i, flags)?); - return Ok(i); + return Ok(start + i); } } @@ -259,17 +285,17 @@ impl FileTable { // Ensure the file descriptor is available. if files[new_fd].is_none() { files[new_fd] = Some(handle.duplicate(new_fd, flags)?); - Ok(0x00) + Ok(0) } else { // If the file descriptor is not available, then we close the // old one and set its handle to the new duplicate handle. let handle = handle.duplicate(new_fd, flags)?; let old = files[new_fd].take().unwrap(); - old.inode.inode().close(old.flags); + old.inode.inode().close(*old.flags.read()); files[new_fd] = Some(handle); - Ok(0x00) + Ok(0) } } @@ -287,29 +313,51 @@ impl FileTable { pub fn deep_clone(&self) -> Self { let files = self.0.read(); + + for handle in files.iter().flatten() { + handle + .inode + .inode() + .open(handle.clone()) + .expect("FileTable::clone: failed to open file"); + } + Self(RwLock::new(files.clone())) } + pub fn debug_open_file(&self, dirent: DirCacheItem, flags: OpenFlags) -> super::Result { + self.log(); + self.open_file(dirent, flags) + } + pub fn open_file(&self, dentry: DirCacheItem, mut flags: OpenFlags) -> super::Result { let mut files = self.0.write(); - // Remove all of the unneccessary flags. + // Remove all of the unnecessary flags. flags.remove(OpenFlags::O_CREAT); flags.remove(OpenFlags::O_DIRECTORY); // Check if a file handle was removed, if so re-use the file handle. if let Some((i, f)) = files.iter_mut().enumerate().find(|e| e.1.is_none()) { - let handle = Arc::new(FileHandle::new(i, dentry, flags)); + let mut handle = Arc::new(FileHandle::new(i, dentry, flags)); + + if let Some(inode) = handle.inode.inode().open(handle.clone())? { + // TODO: should open be called on the inner file as well??? + handle = Arc::new(FileHandle::new(i, inode, flags)) + } - handle.inode.inode().open(flags)?; *f = Some(handle); Ok(i) } else if files.len() < 256 { let fd = files.len(); - let handle = Arc::new(FileHandle::new(fd, dentry, flags)); + let mut handle = Arc::new(FileHandle::new(fd, dentry, flags)); + + if let Some(inode) = handle.inode.inode().open(handle.clone())? { + // TODO: should open be called on the inner file as well??? + handle = Arc::new(FileHandle::new(fd, inode, flags)) + } - handle.inode.inode().open(flags)?; files.push(Some(handle)); Ok(fd) @@ -318,15 +366,19 @@ impl FileTable { } } - /// Closes a file descriptor, so that its no longer referes to any file - /// and can be resued. This function will return false if the provided file + /// Closes a file descriptor, so that its no longer refers to any file + /// and can be reused. This function will return false if the provided file /// descriptor index was invalid. pub fn close_file(&self, fd: usize) -> bool { + // log::warn!("closing filedescriptor {fd} ---- START"); + // crate::unwind::unwind_stack_trace(); + // log::warn!("closing filedescriptor {fd} ---- END"); + let mut files = self.0.write(); if let Some(file) = files.get_mut(fd) { if let Some(handle) = file { - handle.inode.inode().close(handle.flags); + handle.inode.inode().close(*handle.flags.read()); *file = None; return true; diff --git a/src/aero_kernel/src/fs/initramfs.rs b/src/aero_kernel/src/fs/initramfs.rs deleted file mode 100644 index 2cc9a953535..00000000000 --- a/src/aero_kernel/src/fs/initramfs.rs +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use alloc::sync::Arc; -use cpio_reader::Mode; - -use crate::fs::{FileSystemError, Path}; - -use super::cache::DirCacheItem; -use super::ramfs::RamFs; - -use super::{root_dir, FileSystem, LookupMode, Result, MOUNT_MANAGER}; - -lazy_static::lazy_static! { - static ref INIT_FILESYSTEM: Arc = InitRamFs::new(); -} - -struct InitRamFs(Arc); - -impl InitRamFs { - pub fn new() -> Arc { - Arc::new(Self(RamFs::new())) - } -} - -impl FileSystem for InitRamFs { - fn root_dir(&self) -> DirCacheItem { - self.0.root_dir() - } -} - -pub(super) fn init() -> Result<()> { - lazy_static::initialize(&INIT_FILESYSTEM); - - let initrd_module = crate::INITRD_MODULE.get().unwrap(); - let initrd = unsafe { - core::slice::from_raw_parts( - initrd_module.base.as_ptr().unwrap(), - initrd_module.length as usize, - ) - }; - - let mut symlinks = alloc::vec![]; - - for entry in cpio_reader::iter_files(initrd) { - let path = Path::new(entry.name()); - - if entry.mode().contains(Mode::SYMBOLIK_LINK) { - // CPIO symbolically linked file's contain the target path as their contents. - let target = - core::str::from_utf8(entry.file()).map_err(|_| FileSystemError::InvalidPath)?; - - let (parent, _) = path.parent_and_basename(); - - // We need to create symbolically linked files at the end, after all the - // other files. - symlinks.push((alloc::format!("{}/{}", parent.as_str(), target), path)); - continue; - } - - let component_count = path.components().count(); - - let mut cwd = root_dir().clone(); - - for (i, component) in path.components().enumerate() { - if i == component_count - 1 { - cwd.inode().make_ramfs_inode(component, entry.file())?; - } else { - match cwd.inode().lookup(cwd.clone(), component) { - Ok(new_cwd) => cwd = new_cwd, - Err(FileSystemError::EntryNotFound) => { - cwd.inode().mkdir(component)?; - cwd = cwd.inode().lookup(cwd.clone(), component)?; - } - Err(error) => return Err(error), - } - } - } - } - - for (src, target) in symlinks { - let src = super::lookup_path_with(root_dir().clone(), Path::new(&src), LookupMode::None) - .expect(&alloc::format!("your mom {:?}", src)); - let (target_dir, target_name) = target.parent_and_basename(); - - let target = super::lookup_path_with(root_dir().clone(), target_dir, LookupMode::None) - .expect(&alloc::format!("your dad {:?}", target)); - target.inode().link(target_name, src.inode()).unwrap(); - } - - MOUNT_MANAGER.mount(root_dir().clone(), INIT_FILESYSTEM.clone())?; - Ok(()) -} diff --git a/src/aero_kernel/src/fs/inode.rs b/src/aero_kernel/src/fs/inode.rs index da4af7a19db..68caab948f4 100644 --- a/src/aero_kernel/src/fs/inode.rs +++ b/src/aero_kernel/src/fs/inode.rs @@ -1,58 +1,54 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::sync::atomic::{AtomicUsize, Ordering}; use aero_syscall::prelude::{EPollEventFlags, PollEventFlags}; -use aero_syscall::socket::MessageHeader; +use aero_syscall::socket::{MessageFlags, MessageHeader}; use aero_syscall::{MMapFlags, OpenFlags, SyscallError}; -use alloc::sync::Arc; -use alloc::sync::Weak; +use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; use intrusive_collections::UnsafeRef; use spin::Once; -use crate::mem::paging::PhysFrame; +use crate::mem::paging::{PhysFrame, VirtAddr}; use crate::socket::unix::UnixSocket; -use crate::socket::SocketAddr; +use crate::socket::{SocketAddr, SocketAddrRef}; use crate::userland::scheduler; -use crate::utils::sync::BlockQueue; -use crate::utils::sync::Mutex; +use crate::utils::sync::{BMutex, Mutex, WaitQueue}; -use super::cache; -use super::cache::Cacheable; -use super::cache::CachedINode; -use super::cache::{DirCacheItem, INodeCacheItem}; +use super::block::PageCacheItem; +use super::cache::{Cacheable, CachedINode, DirCacheItem, INodeCacheItem}; use super::devfs::DevINode; -use super::{FileSystem, FileSystemError, Result}; +use super::file_table::FileHandle; +use super::path::PathBuf; +use super::{cache, FileSystem, FileSystemError, Path, Result}; static DIR_CACHE_MARKER: AtomicUsize = AtomicUsize::new(0x00); #[derive(Default)] pub struct PollTable { - pub queues: Vec>, + pub queues: Vec>, } impl PollTable { - pub fn insert(&mut self, queue: &BlockQueue) { + pub fn insert(&mut self, queue: &WaitQueue) { queue.insert(scheduler::get_scheduler().current_task()); unsafe { self.queues.push(UnsafeRef::from_raw(queue as *const _)) } } @@ -62,7 +58,7 @@ impl Drop for PollTable { fn drop(&mut self) { let ctask = scheduler::get_scheduler().current_task(); for queue in self.queues.iter() { - queue.remove(ctask.clone()); + queue.remove(&ctask); } } } @@ -70,7 +66,7 @@ impl Drop for PollTable { bitflags::bitflags! { pub struct PollFlags: usize { /// The associated file is available for read operations. - const IN = 1 << 1; + const IN = 1 << 1; /// The associated file is available for write operations. const OUT = 1 << 2; /// Error condition happened on the associated file descriptor. @@ -114,19 +110,34 @@ impl From for PollEventFlags { } } +pub enum MMapPage { + Direct(PhysFrame), + PageCache(PageCacheItem), +} + /// An inode describes a file. An inode structure holds metadata of the /// inode which includes its type, size, the number of links referring to it, /// and the list of blocks holding the file's content. For example device files, /// files on the disk, etc... #[downcastable] pub trait INodeInterface: Send + Sync { + /// Resolves the symbolically linked file and returns the relative path + /// to the file. + /// + /// ## Errors + /// - `FileSystemError::NotSupported` - If the inode is not a symbolic link or the filesystem + /// does not support symbolic links. + fn resolve_link(&self) -> Result { + Err(FileSystemError::NotSupported) + } + /// Returns the inode metadata of `this` inode. fn metadata(&self) -> Result { Err(FileSystemError::NotSupported) } /// Read at the provided `offset` to the given `buffer`. - fn read_at(&self, _offset: usize, _buffer: &mut [u8]) -> Result { + fn read_at(&self, _flags: OpenFlags, _offset: usize, _buffer: &mut [u8]) -> Result { Err(FileSystemError::NotSupported) } @@ -144,12 +155,16 @@ pub trait INodeInterface: Send + Sync { Err(FileSystemError::NotSupported) } - /// Creates a new file with the provoded `name` in the filesystem. + /// Creates a new file with the provided `name` in the filesystem. fn touch(&self, _parent: DirCacheItem, _name: &str) -> Result { Err(FileSystemError::NotSupported) } fn stat(&self) -> Result { + Ok(aero_syscall::Stat::default()) + } + + fn shutdown(&self, _how: usize) -> Result<()> { Err(FileSystemError::NotSupported) } @@ -181,8 +196,18 @@ pub trait INodeInterface: Send + Sync { Err(FileSystemError::NotSupported) } - fn open(&self, _flags: OpenFlags) -> Result<()> { - Ok(()) + fn open(&self, _handle: Arc) -> Result> { + Ok(None) + } + + /// Renames a file (`src`) to `dest`, moving it between directories if required. Any other hard + /// links to the file (as created using [`INodeInterface::link`]) are unaffected. + /// + /// ## Atomicity + /// * If `dest` already exists, it will be atomically replaced. + /// * There can be a window in which both `src` and `dest` refer to the file being renamed. + fn rename(&self, _src: DirCacheItem, _dest: &str) -> Result<()> { + Err(FileSystemError::NotSupported) } fn close(&self, _flags: OpenFlags) {} @@ -204,7 +229,7 @@ pub trait INodeInterface: Send + Sync { Err(FileSystemError::NotSupported) } - /// ## Saftey + /// ## Safety /// /// The caller is responsible for removing the inode from the cache. fn unlink(&self, _name: &str) -> Result<()> { @@ -215,12 +240,20 @@ pub trait INodeInterface: Send + Sync { Err(FileSystemError::NotSupported) } + fn mmap_v2(&self, _offset: usize) -> Result { + log::error!( + "{} does not support mmap_v2!", + core::any::type_name_of_val(self), + ); + Err(FileSystemError::NotSupported) + } + // Socket operations: - fn bind(&self, _address: SocketAddr, _length: usize) -> Result<()> { + fn bind(&self, _address: SocketAddrRef, _length: usize) -> Result<()> { Err(FileSystemError::NotSocket) } - fn connect(&self, _address: SocketAddr, _length: usize) -> Result<()> { + fn connect(&self, _address: SocketAddrRef, _length: usize) -> Result<()> { Err(FileSystemError::NotSocket) } @@ -228,14 +261,31 @@ pub trait INodeInterface: Send + Sync { Err(SyscallError::ENOTSOCK) } - fn accept(&self, _address: Option<&mut SocketAddr>) -> Result> { + fn accept(&self, _address: Option<(VirtAddr, &mut u32)>) -> Result> { Err(FileSystemError::NotSocket) } - fn recv(&self, _message_header: &mut MessageHeader) -> Result { + fn send(&self, _message_hdr: &mut MessageHeader, _flags: MessageFlags) -> Result { + Err(FileSystemError::NotSupported) + } + + fn recv( + &self, + _fd_flags: OpenFlags, + _message_hdr: &mut MessageHeader, + _flags: MessageFlags, + ) -> Result { Err(FileSystemError::NotSocket) } + fn get_peername(&self) -> Result { + Err(FileSystemError::NotSupported) + } + + fn get_sockname(&self) -> Result { + Err(FileSystemError::NotSupported) + } + /// Returns the inner UNIX socket inode if bound to one. fn as_unix_socket(&self) -> Result> { Err(FileSystemError::NotSocket) @@ -245,34 +295,40 @@ pub trait INodeInterface: Send + Sync { Err(FileSystemError::NotSupported) } - fn link(&self, _name: &str, _src: INodeCacheItem) -> Result<()> { + fn link(&self, _name: &str, _src: DirCacheItem) -> Result<()> { + Err(FileSystemError::NotSupported) + } + + fn symlink(&self, _target: &Path) -> Result<()> { Err(FileSystemError::NotSupported) } } -/// Structure representing the curcial, characteristics of an inode. The metadata -/// of an inode can be retrieved by invoking the [INodeInterface::metadata] function. +/// Structure representing the crucial, characteristics of an inode. The metadata +/// of an inode can be retrieved by invoking the [`INodeInterface::metadata`] function. #[derive(Debug, Copy, Clone)] pub struct Metadata { pub id: usize, pub file_type: FileType, - - /// The total size of the content that the inode holds. Set to `0x00` if - /// the inode file type is *not* a file. pub size: usize, - - /// The length of the children's map of the inode. Set to `0x00` if the inode - /// has no children and if the file type of the inode is *not* a directory. pub children_len: usize, } impl Metadata { + pub fn with_file_type(file_type: FileType) -> Self { + Self { + file_type, + id: 0, + size: 0, + children_len: 0, + } + } + #[inline] pub fn id(&self) -> usize { self.id } - #[inline] pub fn file_type(&self) -> FileType { self.file_type } @@ -283,16 +339,18 @@ impl Metadata { } /// Returns [`true`] if the file type of the inode is a directory. - #[inline] pub fn is_directory(&self) -> bool { self.file_type == FileType::Directory } /// Returns [`true`] if the file type of the inode is a socket. - #[inline] pub fn is_socket(&self) -> bool { self.file_type == FileType::Socket } + + pub fn is_symlink(&self) -> bool { + matches!(self.file_type, FileType::Symlink) + } } /// Enum representing the inner contents of a file. The file contents depend on the @@ -306,7 +364,7 @@ pub enum FileContents { /// and is backed by a static byte buffer StaticContent(&'static [u8]), - /// If the file type of the inode is [FileType::Device], in that case this variant + /// If the file type of the inode is [`FileType::Device`], in that case this variant /// is used. Device(Arc), @@ -330,6 +388,7 @@ pub enum FileType { Directory, Device, Socket, + Symlink, } impl From for aero_syscall::SysFileType { @@ -337,8 +396,11 @@ impl From for aero_syscall::SysFileType { match file { FileType::File => aero_syscall::SysFileType::File, FileType::Directory => aero_syscall::SysFileType::Directory, - FileType::Device => aero_syscall::SysFileType::Device, + FileType::Device => aero_syscall::SysFileType::CharDevice, // FIXME: determine if it + // is a character or + // block device. FileType::Socket => aero_syscall::SysFileType::Socket, + FileType::Symlink => aero_syscall::SysFileType::Symlink, } } } @@ -358,7 +420,7 @@ pub(super) struct DirProtectedData { /// A directory entry is basically the mapping of filename to its inode. pub struct DirEntry { - pub(super) data: Mutex, + pub(super) data: BMutex, pub(super) filesystem: Once>, pub(super) cache_marker: usize, } @@ -369,19 +431,23 @@ impl DirEntry { pub fn new(parent: DirCacheItem, inode: INodeCacheItem, name: String) -> DirCacheItem { let dcache = cache::dcache(); - /* - * Helper bool to avoid situations where the directory entry is already cached. The possible - * cases are: - * - * "." (ie. we do not want to re-cache the current directory) - * ".." (ie. we do not want to re-cache the current directory's, parent directory). - */ + // Helper bool to avoid situations where the directory entry is already cached. The + // possible cases are: + // + // "." (ie. we do not want to re-cache the current directory) + // ".." (ie. we do not want to re-cache the current directory's, parent directory). let cache_me = ![".", ".."].contains(&name.as_str()); + let filesystem = if let Some(fs) = inode.weak_filesystem() { + Once::initialized(fs) + } else { + Once::new() + }; + let entry = Self { - data: Mutex::new(DirProtectedData { - parent: Some(parent.clone()), - inode: inode.clone(), + data: BMutex::new(DirProtectedData { + parent: Some(parent), + inode, name, }), @@ -391,11 +457,7 @@ impl DirEntry { 0x00 }, - filesystem: if let Some(filesystem) = inode.weak_filesystem() { - Once::initialized(filesystem) - } else { - Once::new() - }, + filesystem, }; if cache_me { @@ -412,9 +474,9 @@ impl DirEntry { let dcache = cache::dcache(); dcache.make_item_no_cache(Self { - data: Mutex::new(DirProtectedData { + data: BMutex::new(DirProtectedData { parent: None, - inode: inode.clone(), + inode, name, }), @@ -428,7 +490,7 @@ impl DirEntry { let inode = icache.make_item_no_cache(CachedINode::new(inode)); cache::dcache().make_item_no_cache(Self { - data: Mutex::new(DirProtectedData { + data: BMutex::new(DirProtectedData { parent: None, name, @@ -455,7 +517,7 @@ impl DirEntry { .make_local_socket_inode(name.as_str(), inode)?; Ok(cache::dcache().make_item_no_cache(Self { - data: Mutex::new(DirProtectedData { + data: BMutex::new(DirProtectedData { parent: Some(parent), inode: inode.clone(), name, @@ -473,6 +535,14 @@ impl DirEntry { self.data.lock().name.clone() } + pub fn set_name(&self, name: &str) { + self.data.lock().name = name.into(); + } + + pub fn set_parent(&self, parent: DirCacheItem) { + self.data.lock().parent = Some(parent); + } + /// Returns the inner cached inode item of the directory entry. pub fn inode(&self) -> INodeCacheItem { self.data.lock().inode.clone() @@ -491,7 +561,7 @@ impl DirEntry { /// Fetches a cached directory entry item from the directory cache. Returns if /// the provided entry exists in the given parent directory cache. -pub fn fetch_dir_entry(parent: DirCacheItem, name: String) -> Option { +pub fn fetch_dir_entry(parent: &DirCacheItem, name: String) -> Option { let dcache = cache::dcache(); let cache_key = (parent.cache_marker, name); diff --git a/src/aero_kernel/src/fs/mod.rs b/src/aero_kernel/src/fs/mod.rs index 8f7905b47d6..570dbfa5ec5 100644 --- a/src/aero_kernel/src/fs/mod.rs +++ b/src/aero_kernel/src/fs/mod.rs @@ -1,50 +1,51 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::mem; +pub mod path; + +// TODO: Do not re-export this. +pub use path::Path; + use aero_syscall::SyscallError; use alloc::collections::BTreeMap; use alloc::sync::Arc; +use crate::fs::cache::DirCacheImpl; use crate::userland::scheduler; use crate::utils::sync::Mutex; use spin::Once; -use crate::fs::inode::FileType; - -use self::cache::Cacheable; -use self::{cache::DirCacheItem, ramfs::RamFs}; +use self::cache::{Cacheable, DirCacheItem}; pub mod block; pub mod cache; pub mod devfs; pub mod epoll; pub mod eventfd; +pub mod ext2; pub mod file_table; -pub mod initramfs; pub mod inode; pub mod pipe; pub mod procfs; pub mod ramfs; -static ROOT_FS: Once> = Once::new(); +static ROOT_FS: Once> = Once::new(); static ROOT_DIR: Once = Once::new(); lazy_static::lazy_static! { @@ -71,7 +72,7 @@ impl MountManager { Self(Mutex::new(BTreeMap::new())) } - fn mount(&self, directory: DirCacheItem, filesystem: Arc) -> Result<()> { + pub fn mount(&self, directory: DirCacheItem, filesystem: Arc) -> Result<()> { let mut this = self.0.lock(); let mount_key = directory.cache_key(); @@ -84,8 +85,8 @@ impl MountManager { let current_data = directory.data.lock(); let mut root_data = root_dir.data.lock(); - root_data.name = current_data.name.clone(); - root_data.parent = current_data.parent.clone(); + root_data.name.clone_from(¤t_data.name); + root_data.parent.clone_from(¤t_data.parent); mem::drop(root_data); mem::drop(current_data); @@ -102,9 +103,9 @@ impl MountManager { Ok(()) } - fn find_mount(&self, directory: DirCacheItem) -> Result { + fn find_mount(&self, dir: &DirCacheItem) -> Result { let this = self.0.lock(); - let cache_key = directory.cache_key(); + let cache_key = dir.cache_key(); if let Some(mount_point) = this.get(&cache_key) { Ok(mount_point.clone()) @@ -136,6 +137,7 @@ pub enum FileSystemError { ConnectionRefused, NotConnected, WouldBlock, + NoTty, } impl From for SyscallError { @@ -155,63 +157,12 @@ impl From for SyscallError { FileSystemError::IsDir => Self::EISDIR, FileSystemError::NotConnected => Self::ENOTCONN, FileSystemError::WouldBlock => Self::EAGAIN, + FileSystemError::NoTty => Self::ENOTTY, } } } -/// A slice of a path (akin to [str]). -#[derive(Debug)] -pub struct Path(str); - -impl Path { - pub fn new(path: &str) -> &Self { - unsafe { &*(path as *const str as *const Path) } - } - - /// Returns [`true`] if the path is absolute. - pub fn is_absolute(&self) -> bool { - self.0.starts_with('/') - } - - /// Returns an iterator over the components of the path. - pub fn components(&self) -> impl Iterator { - self.0.split("/").filter(|e| *e != "" && *e != ".") - } - - pub fn as_str(&self) -> &str { - &self.0 - } - - pub fn container(&self) -> &Path { - let dir = self.0.rfind("/"); - - match dir { - Some(0) => Path::new(&self.0[1..]), - Some(v) => Path::new(&self.0[v + 1..]), - None => Path::new(&self.0), - } - } - - /// Helper function that returns the parent path and the base name - /// of the path. - pub fn parent_and_basename(&self) -> (&Self, &str) { - if let Some(slash_index) = self.0.rfind('/') { - let parent_dir = if slash_index == 0 { - Path::new("/") - } else { - Path::new(&self.0[..slash_index]) - }; - - let basename = &self.0[(slash_index + 1)..]; - (parent_dir, basename) - } else { - // A relative path without any slashes. - (Path::new(""), &self.0) - } - } -} - -#[derive(Debug, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum LookupMode { None, /// Creates the file if it does not exist. @@ -222,7 +173,10 @@ pub fn lookup_path_with( mut cwd: DirCacheItem, path: &Path, mode: LookupMode, + resolve_last: bool, ) -> Result { + let components_len = path.components().count(); + // Iterate and resolve each component. For example `a`, `b`, and `c` in `a/b/c`. for (i, component) in path.components().enumerate() { match component { @@ -236,14 +190,15 @@ pub fn lookup_path_with( cwd = parent; } - // Else the entry does not have a parent, ie. the current entry is the root aand + // Else the entry does not have a parent, ie. the current entry is the root and // we can't go any further :^) } _ => { // After we have resolved all of the special cases that might occur in a path, now // we have to resolve the directory entry itself. For example `a` in `./a/`. - let cache_entry = inode::fetch_dir_entry(cwd.clone(), String::from(component)); + let cache_entry = inode::fetch_dir_entry(&cwd, String::from(component)); + let parent = cwd.clone(); if let Some(entry) = cache_entry { cwd = entry; @@ -255,13 +210,23 @@ pub fn lookup_path_with( if err == FileSystemError::EntryNotFound && mode == LookupMode::Create => { - if i == path.components().count() - 1 { + if i == components_len - 1 { cwd = cwd.inode().touch(cwd.clone(), component)?; } else { // todo: fix this shit cwd.inode().mkdir(component)?; - cwd = - lookup_path_with(cwd, Path::new(component), LookupMode::None)?; + cwd = match lookup_path_with( + cwd.clone(), + Path::new(component), + LookupMode::None, + resolve_last, + ) { + Ok(x) => x, + Err(e) => { + dbg!(component, cwd.absolute_path()); + return Err(dbg!(e)); + } + }; } } @@ -269,8 +234,24 @@ pub fn lookup_path_with( } } - if cwd.inode().metadata()?.file_type == FileType::Directory { - if let Ok(mount_point) = MOUNT_MANAGER.find_mount(cwd.clone()) { + let inode = cwd.inode(); + let metadata = inode.metadata()?; + + if metadata.is_symlink() && resolve_last { + let resolved_path = inode.resolve_link()?; + + cwd = lookup_path_with( + if resolved_path.is_absolute() { + root_dir().clone() + } else { + parent + }, + resolved_path.as_ref(), + LookupMode::None, + resolve_last, + )?; + } else if metadata.is_directory() { + if let Ok(mount_point) = MOUNT_MANAGER.find_mount(&cwd) { cwd = mount_point.root_entry; } } @@ -281,24 +262,15 @@ pub fn lookup_path_with( Ok(cwd) } -pub fn lookup_path_with_mode(path: &Path, mode: LookupMode) -> Result { - let cwd = if !path.is_absolute() { - scheduler::get_scheduler().current_task().get_cwd_dirent() - } else { - root_dir().clone() - }; - - lookup_path_with(cwd, path, mode) -} - pub fn lookup_path(path: &Path) -> Result { let cwd = if !path.is_absolute() { - scheduler::get_scheduler().current_task().get_cwd_dirent() + scheduler::current_thread().cwd_dirent() } else { root_dir().clone() }; - lookup_path_with(cwd, path, LookupMode::None) + // TODO:Keep `resolve_last` set to true as a default? + lookup_path_with(cwd, path, LookupMode::None, true) } pub fn root_dir() -> &'static DirCacheItem { @@ -307,26 +279,5 @@ pub fn root_dir() -> &'static DirCacheItem { pub fn init() -> Result<()> { cache::init(); - - let filesystem = RamFs::new(); - - ROOT_FS.call_once(|| filesystem.clone()); - ROOT_DIR.call_once(|| filesystem.root_dir().clone()); - - root_dir().inode().mkdir("dev")?; - root_dir().inode().mkdir("home")?; - root_dir().inode().mkdir("tmp")?; - root_dir().inode().mkdir("proc")?; - root_dir().inode().mkdir("var")?; - - initramfs::init()?; - log::info!("installed initramfs"); - - devfs::init()?; - log::info!("installed devfs"); - - procfs::init()?; - log::info!("installed procfs"); - Ok(()) } diff --git a/src/aero_kernel/src/fs/path.rs b/src/aero_kernel/src/fs/path.rs new file mode 100644 index 00000000000..c7df40ffc18 --- /dev/null +++ b/src/aero_kernel/src/fs/path.rs @@ -0,0 +1,201 @@ +use core::borrow::Borrow; +use core::fmt::Display; +use core::ops::Deref; + +use alloc::borrow::ToOwned; +use alloc::vec::Vec; + +/// A slice of a path (akin to [str]). +#[derive(Debug)] +pub struct Path(str); + +impl Path { + pub fn new(path: &str) -> &Self { + unsafe { &*(path as *const str as *const Path) } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Returns [`true`] if the path is absolute. + pub fn is_absolute(&self) -> bool { + self.0.starts_with('/') + } + + /// Returns an iterator over the components of the path. + pub fn components(&self) -> impl Iterator { + self.0.split('/').filter(|e| !e.is_empty() && *e != ".") + } + + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. + /// + /// If `path` is absolute, it replaces the current path. + /// + /// See [`PathBuf::push`] for more details on what it means to adjoin a path. + pub fn join>(&self, path: P) -> PathBuf { + let mut result = self.to_owned(); + result.push(path); + result + } + + /// Helper function that returns the parent path and the base name + /// of the path. + pub fn parent_and_basename(&self) -> (&Self, &str) { + if let Some(slash_index) = self.0.rfind('/') { + let parent_dir = if slash_index == 0 { + Path::new("/") + } else { + Path::new(&self.0[..slash_index]) + }; + + let basename = &self.0[(slash_index + 1)..]; + (parent_dir, basename) + } else { + // A relative path without any slashes. + (Path::new(""), &self.0) + } + } + + #[inline] + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + /// Returns the byte length of the path. + pub fn len(&self) -> usize { + self.0.len() + } +} + +impl Borrow for PathBuf { + #[inline] + fn borrow(&self) -> &Path { + self.deref() + } +} + +impl ToOwned for Path { + type Owned = PathBuf; + + #[inline] + fn to_owned(&self) -> Self::Owned { + PathBuf(self.0.to_owned()) + } +} + +impl AsRef for Path { + #[inline] + fn as_ref(&self) -> &Path { + self + } +} + +impl AsRef for &str { + #[inline] + fn as_ref(&self) -> &Path { + Path::new(self) + } +} + +impl AsRef for String { + #[inline] + fn as_ref(&self) -> &Path { + Path::new(self) + } +} + +/// An owned, mutable path (akin to [`String`]). +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PathBuf(String); + +impl PathBuf { + /// Allocates an empty `PathBuf`. + #[inline] + pub fn new() -> Self { + Self(String::new()) + } + + #[inline] + fn as_mut_vec(&mut self) -> &mut Vec { + // TODO: safety? + unsafe { self.0.as_mut_vec() } + } + + /// Extends `self` with `path`. + /// + /// If `path` is absolute, it replaces the current path. + pub fn push>(&mut self, path: P) { + let path = path.as_ref(); + + // absolute `path` replaces `self` + if path.is_absolute() { + self.as_mut_vec().truncate(0); + } + + let need_sep = self.0.chars().last().is_some_and(|c| c != '/'); + + // TODO: verbatim pahts need . and .. removed + + if need_sep { + self.0.push('/'); + } + + self.0.push_str(path.as_str()); + } +} + +impl Default for PathBuf { + #[inline] + fn default() -> Self { + PathBuf::new() + } +} + +impl From for PathBuf { + #[inline] + fn from(path: String) -> Self { + Self(path) + } +} + +impl From<&str> for PathBuf { + fn from(value: &str) -> Self { + Self(value.to_owned()) + } +} + +impl Deref for PathBuf { + type Target = Path; + + #[inline] + fn deref(&self) -> &Self::Target { + Path::new(&self.0) + } +} + +impl AsRef for PathBuf { + #[inline] + fn as_ref(&self) -> &Path { + self + } +} + +impl From for String { + #[inline] + fn from(val: PathBuf) -> Self { + val.0 + } +} + +impl Display for PathBuf { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.0.fmt(f) + } +} diff --git a/src/aero_kernel/src/fs/pipe.rs b/src/aero_kernel/src/fs/pipe.rs index 4148ba33c5d..d55b4b5d3af 100644 --- a/src/aero_kernel/src/fs/pipe.rs +++ b/src/aero_kernel/src/fs/pipe.rs @@ -1,18 +1,39 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + use core::sync::atomic::{AtomicUsize, Ordering}; use aero_syscall::OpenFlags; use alloc::sync::Arc; +use spin::Once; use crate::utils::buffer::Buffer; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueFlags}; +use super::cache::DirCacheItem; +use super::file_table::FileHandle; use super::inode::{INodeInterface, PollFlags, PollTable}; +use super::FileSystemError; pub struct Pipe { queue: Mutex, - readers: BlockQueue, - writers: BlockQueue, + readers: WaitQueue, + writers: WaitQueue, /// The number of writers currently connected to the pipe. num_writers: AtomicUsize, @@ -23,27 +44,27 @@ impl Pipe { Arc::new(Self { queue: Mutex::new(Buffer::new()), - readers: BlockQueue::new(), - writers: BlockQueue::new(), + readers: WaitQueue::new(), + writers: WaitQueue::new(), num_writers: AtomicUsize::new(0), }) } - /// Returns whether the pipe has active writers. - pub fn has_active_writers(&self) -> usize { + /// Returns the number of active writers to the pipe. + pub fn active_writers(&self) -> usize { self.num_writers.load(Ordering::SeqCst) } } impl INodeInterface for Pipe { - fn open(&self, flags: OpenFlags) -> super::Result<()> { + fn open(&self, handle: Arc) -> super::Result> { // Write end of the pipe: - if flags.contains(OpenFlags::O_WRONLY) { + if handle.flags().contains(OpenFlags::O_WRONLY) { self.num_writers.fetch_add(1, Ordering::SeqCst); } - Ok(()) + Ok(None) } fn close(&self, flags: OpenFlags) { @@ -53,21 +74,25 @@ impl INodeInterface for Pipe { // There are no active writers and no data to read (reached EOF). if active_writers == 0 { - self.readers.notify_complete(); + self.readers.notify_all(); } } } - fn read_at(&self, _offset: usize, buf: &mut [u8]) -> super::Result { - let mut buffer = self.readers.block_on(&self.queue, |lock| { - lock.has_data() || !self.has_active_writers() == 0 + fn read_at(&self, flags: OpenFlags, _offset: usize, buf: &mut [u8]) -> super::Result { + if flags.is_nonblock() && !self.queue.lock_irq().has_data() { + return Err(FileSystemError::WouldBlock); + } + + let mut buffer = self.readers.wait(flags.into(), &self.queue, |lock| { + lock.has_data() || self.active_writers() == 0 })?; let read = buffer.read_data(buf); if read > 0 { // TODO: Notify only the first process - self.writers.notify_complete(); + self.writers.notify_all(); } Ok(read) @@ -75,16 +100,16 @@ impl INodeInterface for Pipe { fn write_at(&self, _offset: usize, buf: &[u8]) -> super::Result { let res = self.queue.lock_irq().write_data(buf); - self.readers.notify_complete(); + self.readers.notify_all(); Ok(res) } fn poll(&self, table: Option<&mut PollTable>) -> super::Result { - table.map(|e| { - e.insert(&self.readers); - e.insert(&self.writers) - }); + if let Some(table) = table { + table.insert(&self.readers); + table.insert(&self.writers); + } let mut flags = PollFlags::OUT; diff --git a/src/aero_kernel/src/fs/procfs.rs b/src/aero_kernel/src/fs/procfs.rs index ed3c398a3a7..35d4245e88d 100644 --- a/src/aero_kernel/src/fs/procfs.rs +++ b/src/aero_kernel/src/fs/procfs.rs @@ -1,22 +1,44 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + use core::sync::atomic::{AtomicUsize, Ordering}; +use aero_syscall::OpenFlags; +use alloc::borrow::ToOwned; use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; +use alloc::string::ToString; use alloc::sync::{Arc, Weak}; use spin::{Once, RwLock}; +use crate::fs; use crate::fs::inode::FileType; use crate::arch::tls; +use crate::userland::scheduler; -use super::cache; use super::cache::*; +use super::{cache, FileSystem, Path, MOUNT_MANAGER}; +use super::inode::{DirEntry, INodeInterface, Metadata}; use super::FileSystemError; -use super::inode::*; -use super::*; +// TODO: put this mf in prelude +use alloc::vec; fn push_string_if_some(map: &mut serde_json::Value, key: &str, value: Option) { if let Some(value) = value { @@ -41,39 +63,39 @@ fn get_cpuinfo_cached() -> &'static str { static CACHED: Once = Once::new(); CACHED.call_once(|| { - use alloc::vec; use serde_json::*; let mut data = json!({ "processors": [] }); - data.get_mut("processors") + if let Some(processors) = data + .get_mut("processors") .and_then(|processors| processors.as_array_mut()) - .map(|processors| { - let mut cpu_info = vec![]; - - #[cfg(target_arch = "x86_64")] - tls::for_cpu_info_cached(|info| { - let mut processor = json!({}); + { + let mut cpu_info = vec![]; - processor["id"] = Value::Number(Number::from(info.cpuid)); - processor["fpu"] = Value::Bool(info.fpu); + #[cfg(target_arch = "x86_64")] + tls::for_cpu_info_cached(|info| { + let mut processor = json!({}); - push_string_if_some(&mut processor, "brand", info.brand.clone()); - push_string_if_some(&mut processor, "vendor", info.vendor.clone()); + processor["id"] = Value::Number(Number::from(info.cpuid)); + processor["fpu"] = Value::Bool(info.fpu); - processor["features"] = Value::Array( - info.features - .iter() - .map(|feature| Value::String(feature.to_string())) - .collect(), - ); + push_string_if_some(&mut processor, "brand", info.brand.clone()); + push_string_if_some(&mut processor, "vendor", info.vendor.clone()); - cpu_info.push(processor); - }); + processor["features"] = Value::Array( + info.features + .iter() + .map(|feature| Value::String(feature.to_string())) + .collect(), + ); - *processors = cpu_info; + cpu_info.push(processor); }); + *processors = cpu_info; + } + data.to_string() }) } @@ -92,6 +114,7 @@ struct ProcINode { enum FileContents { CpuInfo, CmdLine, + SelfMaps, None, } @@ -129,7 +152,7 @@ impl LockedProcINode { name: &str, file_type: FileType, contents: FileContents, - ) -> Result { + ) -> fs::Result { let icache = cache::icache(); let mut this = self.0.write(); @@ -161,12 +184,30 @@ impl LockedProcINode { } impl INodeInterface for LockedProcINode { - fn read_at(&self, offset: usize, buffer: &mut [u8]) -> Result { + fn read_at(&self, _flags: OpenFlags, offset: usize, buffer: &mut [u8]) -> fs::Result { let this = self.0.read(); let data = match &this.contents { - FileContents::CpuInfo => Ok(get_cpuinfo_cached()), - FileContents::CmdLine => Ok(get_cmdline_cached()), + FileContents::CpuInfo => Ok(get_cpuinfo_cached().to_owned()), + FileContents::CmdLine => Ok(get_cmdline_cached().to_owned()), + + FileContents::SelfMaps => { + let current_thread = scheduler::current_thread(); + let mut result = serde_json::json!({ "maps": [] }); + let maps = result.get_mut("maps").unwrap().as_array_mut().unwrap(); + + current_thread.vm().for_each_mapping(|map| { + maps.push(serde_json::json!({ + "start": map.start_addr.as_u64(), + "end": map.end_addr.as_u64(), + // "flags": map.flags.bits(), + // do we need to tell if is shared? + "protection": map.protection().bits(), + })); + }); + + Ok(result.to_string()) + } _ => Err(FileSystemError::NotSupported), }?; @@ -177,21 +218,17 @@ impl INodeInterface for LockedProcINode { Ok(count) } - fn lookup(&self, dir: DirCacheItem, name: &str) -> Result { + fn lookup(&self, dir: DirCacheItem, name: &str) -> fs::Result { let this = self.0.read(); let child = this .children .get(name) .ok_or(FileSystemError::EntryNotFound)?; - Ok(DirEntry::new( - dir.clone(), - child.clone(), - String::from(name), - )) + Ok(DirEntry::new(dir, child.clone(), String::from(name))) } - fn metadata(&self) -> Result { + fn metadata(&self) -> fs::Result { let this = self.0.read(); Ok(Metadata { @@ -202,7 +239,7 @@ impl INodeInterface for LockedProcINode { }) } - fn dirent(&self, parent: DirCacheItem, index: usize) -> Result> { + fn dirent(&self, parent: DirCacheItem, index: usize) -> fs::Result> { let this = self.0.read(); if this.file_type != FileType::Directory { @@ -213,7 +250,7 @@ impl INodeInterface for LockedProcINode { 0x00 => Some(DirEntry::new( parent, // UNWRAP: The inner node value should not be dropped. - this.node.upgrade().unwrap().into(), + this.node.upgrade().unwrap(), String::from("."), )), @@ -221,7 +258,7 @@ impl INodeInterface for LockedProcINode { Some(DirEntry::new( parent, // UNWRAP: The inner node value should not be dropped. - this.node.upgrade().unwrap().into(), + this.node.upgrade().unwrap(), String::from(".."), )) } @@ -247,7 +284,7 @@ struct ProcFs { } impl ProcFs { - pub fn new() -> Result> { + pub fn new() -> fs::Result> { let icache = cache::icache(); let root_node = Arc::new(LockedProcINode::new(ProcINode::default())); @@ -272,7 +309,7 @@ impl ProcFs { inode.init( &ramfs.root_inode.downgrade(), - &&root_cached.downgrade(), + &root_cached.downgrade(), &Arc::downgrade(&ramfs), FileType::Directory, ); @@ -280,6 +317,11 @@ impl ProcFs { inode.make_inode("cpuinfo", FileType::File, FileContents::CpuInfo)?; inode.make_inode("cmdline", FileType::File, FileContents::CmdLine)?; + let proc_self = inode.make_inode("self", FileType::Directory, FileContents::None)?; + let proc_self = proc_self.downcast_arc::().unwrap(); + + proc_self.make_inode("maps", FileType::File, FileContents::SelfMaps)?; + Ok(ramfs) } @@ -305,7 +347,7 @@ impl FileSystem for ProcFs { static PROC_FS: Once> = Once::new(); -pub fn init() -> Result<()> { +pub fn init() -> fs::Result<()> { let fs = ProcFs::new()?; let fs = PROC_FS.call_once(|| fs); diff --git a/src/aero_kernel/src/fs/ramfs.rs b/src/aero_kernel/src/fs/ramfs.rs index 2401653a10c..8db73c92cc8 100644 --- a/src/aero_kernel/src/fs/ramfs.rs +++ b/src/aero_kernel/src/fs/ramfs.rs @@ -1,31 +1,25 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -//! Implementation of in-memory filesystem. This is used for temporary filesystems (e.g. dev, tmp) and -//! since Aero currently does not have support for actual disk filesystems (e.g. ex2 and FAT32), ram-fs is -//! used as the root filesystem. +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::sync::atomic::{AtomicUsize, Ordering}; -use aero_syscall::MMapFlags; +use aero_syscall::{MMapFlags, OpenFlags}; use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; +use alloc::string::ToString; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; @@ -34,11 +28,13 @@ use spin::RwLock; use crate::mem::paging::*; use crate::utils::sync::Mutex; -use super::cache::{self, CacheWeak}; -use super::cache::{CachedINode, DirCacheItem, INodeCacheItem, INodeCacheWeakItem}; +use super::cache::{ + self, CacheWeak, CachedINode, DirCacheItem, INodeCacheItem, INodeCacheWeakItem, +}; use super::devfs::DevINode; -use super::inode::{DirEntry, FileType, INodeInterface, PollFlags, PollTable}; -use super::inode::{FileContents, Metadata}; +use super::inode::{ + DirEntry, FileContents, FileType, INodeInterface, MMapPage, Metadata, PollFlags, PollTable, +}; use super::{FileSystem, FileSystemError, Result}; #[derive(Default)] @@ -215,7 +211,7 @@ impl INodeInterface for LockedRamINode { 0x00 => Some(DirEntry::new( parent, // UNWRAP: The inner node value should not be dropped. - this.node.upgrade().unwrap().into(), + this.node.upgrade().unwrap(), String::from("."), )), @@ -223,7 +219,7 @@ impl INodeInterface for LockedRamINode { Some(DirEntry::new( parent, // UNWRAP: The inner node value should not be dropped. - this.node.upgrade().unwrap().into(), + this.node.upgrade().unwrap(), String::from(".."), )) } @@ -240,7 +236,7 @@ impl INodeInterface for LockedRamINode { fn unlink(&self, name: &str) -> Result<()> { let mut this = self.0.write(); - if let Some(_) = this.children.remove(name) { + if this.children.remove(name).is_some() { Ok(()) } else { Err(FileSystemError::EntryNotFound) @@ -255,14 +251,17 @@ impl INodeInterface for LockedRamINode { let mut vec = vec.lock(); vec.resize(size, 0); - return Ok(()); + Ok(()) } - _ => Err(FileSystemError::NotSupported), + _ => { + log::warn!("ramfs: truncation is not supported"); + Ok(()) + } } } - fn read_at(&self, offset: usize, buffer: &mut [u8]) -> Result { + fn read_at(&self, flags: OpenFlags, offset: usize, buffer: &mut [u8]) -> Result { let this = self.0.read(); match &this.contents { @@ -274,7 +273,7 @@ impl INodeInterface for LockedRamINode { let size = core::cmp::min(buffer.len(), vec.len() - offset); - for (i, b) in (&vec.as_slice()[offset..offset + size]).iter().enumerate() { + for (i, b) in vec.as_slice()[offset..offset + size].iter().enumerate() { buffer[i] = *b; } @@ -284,7 +283,7 @@ impl INodeInterface for LockedRamINode { FileContents::StaticContent(static_buffer) => { let size = core::cmp::min(buffer.len(), static_buffer.len() - offset); - for (i, b) in (&static_buffer[offset..offset + size]).iter().enumerate() { + for (i, b) in static_buffer[offset..offset + size].iter().enumerate() { buffer[i] = *b; } @@ -295,14 +294,29 @@ impl INodeInterface for LockedRamINode { let device = device.clone(); drop(this); - device.read_at(offset, buffer) + device.read_at(flags, offset, buffer) } - FileContents::Socket(e) => e.read_at(offset, buffer), + FileContents::Socket(e) => e.read_at(flags, offset, buffer), FileContents::None => Err(FileSystemError::NotSupported), } } + fn open(&self, handle: Arc) -> Result> { + let this = self.0.read(); + + match &this.contents { + FileContents::Device(device) => { + let device = device.clone(); + drop(this); + + device.open(handle) + } + + _ => Ok(None), + } + } + fn metadata(&self) -> Result { let this = self.0.read(); @@ -310,7 +324,8 @@ impl INodeInterface for LockedRamINode { id: this.id, file_type: this.file_type, size: match &this.contents { - FileContents::Content(bytes) => bytes.lock().len(), // Temporary value dropped and lock is unlocked! + FileContents::Content(bytes) => bytes.lock().len(), // Temporary value dropped + // and lock is unlocked! FileContents::StaticContent(bytes) => bytes.len(), _ => 0x00, }, @@ -369,6 +384,21 @@ impl INodeInterface for LockedRamINode { } } + fn mmap_v2(&self, offset: usize) -> Result { + let this = self.0.read(); + + match &this.contents { + FileContents::Device(dev) => { + let device = dev.clone(); + drop(this); + + device.mmap_v2(offset) + } + + _ => todo!(), + } + } + fn lookup(&self, dir: DirCacheItem, name: &str) -> Result { let this = self.0.read(); let child = this @@ -376,11 +406,7 @@ impl INodeInterface for LockedRamINode { .get(name) .ok_or(FileSystemError::EntryNotFound)?; - Ok(DirEntry::new( - dir.clone(), - child.clone(), - String::from(name), - )) + Ok(DirEntry::new(dir, child.clone(), String::from(name))) } fn as_unix_socket(&self) -> Result> { @@ -412,7 +438,9 @@ impl INodeInterface for LockedRamINode { Some(self.0.read().filesystem.clone()) } - fn link(&self, name: &str, src: INodeCacheItem) -> Result<()> { + fn link(&self, name: &str, src: DirCacheItem) -> Result<()> { + let src = src.inode(); + // ensure: The dest inode (self) is a directory. if self.metadata()?.file_type() != FileType::Directory { return Err(FileSystemError::NotDirectory); @@ -428,7 +456,7 @@ impl INodeInterface for LockedRamINode { { let this = self.0.read(); - if this.children.iter().find(|(e, _)| e == &name).is_some() { + if this.children.iter().any(|(e, _)| e == name) { return Err(FileSystemError::EntryExists); } } @@ -436,7 +464,7 @@ impl INodeInterface for LockedRamINode { let mut this = self.0.write(); // Create the link! - this.children.insert(name.to_string(), src.clone()); + this.children.insert(name.to_string(), src); Ok(()) } } @@ -474,7 +502,7 @@ impl RamFs { .unwrap() .init( &ramfs.root_inode.downgrade(), - &&root_cached.downgrade(), + &root_cached.downgrade(), &Arc::downgrade(&ramfs), FileType::Directory, ); diff --git a/src/aero_kernel/src/logger.rs b/src/aero_kernel/src/logger.rs index 4811e6d59f8..19d43533ec0 100644 --- a/src/aero_kernel/src/logger.rs +++ b/src/aero_kernel/src/logger.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::fmt::Write; use core::sync::atomic::{AtomicBool, Ordering}; @@ -50,51 +48,46 @@ impl log::Log for AeroLogger { let line = record.line().unwrap_or(0); - if let Some(pp) = record.module_path() { - // Only log the vm logs if the vmlog feature is enabled ;^). - if pp == "aero_kernel::userland::vm" && !cfg!(feature = "vmlog") { - return; - } - } - let level = record.level(); let rendy_dbg = RENDY_DEBUG.load(Ordering::Relaxed); - macro log_ln($($arg:tt)*) { - serial_println!("{}", format_args!($($arg)*)); - if rendy_dbg { $crate::rendy::println!("{}", format_args!($($arg)*)); } + macro generic_log($($arg:tt)*) { + { + serial_print!("{}", format_args!($($arg)*)); + if rendy_dbg { + $crate::rendy::print!("{}", format_args!($($arg)*)); + } + } } // Append the log message to the log ring buffer. let mut log_ring = LOG_RING_BUFFER.get().unwrap().lock_irq(); let _ = writeln!(log_ring, "[{}] {}", level, record.args()); - serial_print!("\x1b[37;1m{file}:{line} "); + let ticks = crate::arch::time::get_uptime_ticks(); + serial_print!("\x1b[37;1m[{}] {file}:{line} ", ticks); if scheduler::is_initialized() { // fetch the current task, grab the TID and PID. - scheduler::get_scheduler() - .inner - .current_task_optional() - .map(|task| { - serial_print!( - "(tid={}, pid={}) ", - task.tid().as_usize(), - task.pid().as_usize() - ); - }); + if let Some(task) = scheduler::get_scheduler().current_task_optional() { + serial_print!( + "(tid={}, pid={}) ", + task.tid().as_usize(), + task.pid().as_usize() + ); + } } match record.level() { - Level::Info => serial_print!("\x1b[32;1minfo "), // green info - Level::Warn => serial_print!("\x1b[33;1mwarn "), // yellow warn - Level::Error => serial_print!("\x1b[32;1merror "), // red error - Level::Debug => serial_print!("\x1b[35;1mdebug "), // gray debug - Level::Trace => serial_print!("\x1b[34;1mtrace "), // blue trace + Level::Info => generic_log!("\x1b[32;1minfo "), // green info + Level::Warn => generic_log!("\x1b[33;1mwarn "), // yellow warn + Level::Error => generic_log!("\x1b[32;1merror "), // red error + Level::Debug => generic_log!("\x1b[35;1mdebug "), // gray debug + Level::Trace => generic_log!("\x1b[34;1mtrace "), // blue trace } - serial_print!("\x1b[0m"); - log_ln!("{}", record.args()); + generic_log!("\x1b[0m"); + generic_log!("{}\n", record.args()); } } @@ -103,19 +96,20 @@ impl log::Log for AeroLogger { /// Force-unlocks the logger ring buffer to prevent a deadlock. /// -/// ## Saftey +/// ## Safety /// This method is not memory safe and should be only used when absolutely necessary. #[inline] pub unsafe fn force_unlock() { - LOG_RING_BUFFER.get().map(|l| l.force_unlock()); + if let Some(l) = LOG_RING_BUFFER.get() { + l.force_unlock() + } } -pub fn get_log_buffer<'a>() -> String { +pub fn get_log_buffer() -> String { LOG_RING_BUFFER .get() .map(|l| String::from(l.lock_irq().extract())) .expect("log: attempted to get the log ring buffer before it was initialized") - .clone() } #[inline] diff --git a/src/aero_kernel/src/main.rs b/src/aero_kernel/src/main.rs index f43d524c6e5..4330c930589 100644 --- a/src/aero_kernel/src/main.rs +++ b/src/aero_kernel/src/main.rs @@ -1,24 +1,23 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! # Aero -//! Aero is a new modern, unix based operating system. It is being developed for educational purposes. +//! Aero is a new modern, unix based operating system. It is being developed for educational +//! purposes. //! //! ## Code organization and architecture //! The code is divided into different *modules*, each representing a *subsystem* of the kernel. @@ -27,46 +26,60 @@ //! * #![feature( - custom_test_frameworks, - alloc_error_handler, - lang_items, - panic_info_message, - decl_macro, - ptr_internals, - linked_list_cursors, - extern_types, - new_uninit, - box_syntax, - step_trait, - const_btree_new, - prelude_import, - allocator_api, - nonnull_slice_from_raw_parts + custom_test_frameworks, // https://github.com/rust-lang/rust/issues/50297 + alloc_error_handler, // https://github.com/rust-lang/rust/issues/51540 + lang_items, // No tracking issue + decl_macro, // https://github.com/rust-lang/rust/issues/39412 + ptr_internals, // No tracking issue + linked_list_cursors, // https://github.com/rust-lang/rust/issues/58533 + extern_types, // https://github.com/rust-lang/rust/issues/43467 + step_trait, // https://github.com/rust-lang/rust/issues/42168 + prelude_import, // No tracking issue + allocator_api, // https://github.com/rust-lang/rust/issues/32838 + maybe_uninit_write_slice, // https://github.com/rust-lang/rust/issues/79995 + slice_ptr_get, // https://github.com/rust-lang/rust/issues/74265 + maybe_uninit_as_bytes, // https://github.com/rust-lang/rust/issues/93092 + const_trait_impl, // https://github.com/rust-lang/rust/issues/67792 + int_roundings, // https://github.com/rust-lang/rust/issues/88581 + naked_functions, // https://github.com/rust-lang/rust/issues/32408 + cfg_match, // https://github.com/rust-lang/rust/issues/115585 + associated_type_defaults, + new_zeroed_alloc, // https://github.com/rust-lang/rust/issues/129396 + sync_unsafe_cell, )] +// TODO(andypython): can we remove the dependency of "prelude_import" and "lang_items"? +// `lang_items` => is currently used for the personality function (`rust_eh_personality`). +// `prelude_import` => is currently just used to re-export alloc prelude. This just makes the +// files overall more readable. +#![allow(internal_features)] #![deny(trivial_numeric_casts, unused_allocation)] #![test_runner(crate::tests::test_runner)] #![no_std] #![no_main] #![reexport_test_harness_main = "test_main"] +#![warn(clippy::needless_pass_by_value)] +#![deny(clippy::ptr_as_ptr)] +#![allow(binary_asm_labels)] #[macro_use] extern crate aero_proc; mod prelude { + #[allow(unused)] pub mod rust_2021 { // Since asm is used almost all over the kernel, its a better idea // to add it to the prelude. pub use core::arch::asm; pub use core::prelude::rust_2021::*; - pub use core::prelude::v1::*; pub use alloc::string::String; + pub use crate::rendy::dbg; pub use static_assertions::*; } } -use limine::LimineFile; +#[allow(unused)] #[prelude_import] pub use prelude::rust_2021::*; @@ -82,6 +95,7 @@ mod fs; mod logger; mod mem; mod modules; +mod net; mod rendy; mod socket; mod syscall; @@ -103,12 +117,37 @@ use self::userland::task::Task; static AERO_SYSTEM_ALLOCATOR: LockedHeap = LockedHeap::new_uninit(); static mut PHYSICAL_MEMORY_OFFSET: VirtAddr = VirtAddr::zero(); -static INITRD_MODULE: spin::Once<&LimineFile> = spin::Once::new(); const IO_VIRTUAL_BASE: VirtAddr = VirtAddr::new(0xffffff0000000000); +const STT_GNU_IFUNC: u32 = 37; + +pub fn relocate_self() { + use xmas_elf::sections::SectionData; + + let unwind_info = unwind::UNWIND_INFO.get().unwrap(); + let kernel_elf = &unwind_info.kernel_elf; + + for section in kernel_elf.section_iter() { + if let Ok(SectionData::Rela64(rela)) = section.get_data(kernel_elf) { + for item in rela { + if item.get_type() != STT_GNU_IFUNC { + continue; + } + + let offset = unsafe { &mut *(item.get_offset() as *mut usize) }; + + let resolver_ptr = item.get_addend() as *const u8; + let resolver: fn() -> usize = unsafe { core::mem::transmute(resolver_ptr) }; + + *offset = resolver(); + } + } + } +} + fn aero_main() -> ! { - // NOTE: In this function we only want to initialize essential serivces, including + // NOTE: In this function we only want to initialize essential services, including // the task scheduler. Rest of the initializing (including kernel modules) should go // into the kernel main thread function instead. fs::init().unwrap(); @@ -128,7 +167,9 @@ fn aero_main() -> ! { // Now that all of the essential initialization is done we are going to schedule // the kernel main thread. let init = Task::new_kernel(kernel_main_thread, true); + let kdbg = Task::new_kernel(kernel_dbg_thread, true); scheduler::get_scheduler().register_task(init); + scheduler::get_scheduler().register_task(kdbg); unsafe { interrupts::enable_interrupts(); @@ -142,20 +183,14 @@ fn aero_main() -> ! { } fn kernel_main_thread() { - let mut address_space = mem::AddressSpace::this(); - let mut offset_table = address_space.offset_page_table(); - modules::init(); log::info!("loaded kernel modules"); - #[cfg(target_arch = "x86_64")] - arch::enable_acpi(); + net::init(); + log::info!("initialized networking stack"); #[cfg(target_arch = "x86_64")] - drivers::pci::init(&mut offset_table); - log::info!("loaded PCI driver"); - - fs::block::launch().unwrap(); + arch::enable_acpi(); #[cfg(test)] test_main(); @@ -175,6 +210,62 @@ fn kernel_main_thread() { unreachable!() } +fn kernel_dbg_thread() { + use core::fmt::Write; + + use crate::drivers::uart::{self, LineStatus, COM_1}; + use crate::userland::task::TaskId; + use crate::utils::sync::{WaitQueue, WaitQueueFlags}; + + uart::setup_interrupts(); + + let input_wq = WaitQueue::new(); + let this_task = scheduler::current_thread(); + uart::register_listener(this_task.clone()); + + let com_1 = COM_1.get().unwrap(); + + loop { + let mut input = String::new(); + + loop { + let mut com_1 = input_wq + .wait(WaitQueueFlags::empty(), com_1, |com_1| { + com_1.line_status().contains(LineStatus::INPUT_FULL) + }) + .unwrap(); + + let c = com_1.read_byte() as char; + + if c == '\r' { + writeln!(com_1).unwrap(); + break; + } + + input.push(c); + write!(com_1, "{c}").unwrap(); + } + + let mut commands = input.split_whitespace(); + + if let Some(name) = commands.next() { + match name { + "ps" => scheduler::get_scheduler().log_ptable(), + "wake" => { + log::warn!("kdbg: forcefully waking up task"); + let id = commands.next().unwrap().parse::().unwrap(); + scheduler::get_scheduler() + .find_task(TaskId::new(id)) + .unwrap() + .wake_up(); + } + + _ => log::warn!("kdbg: unknown command {name:?}"), + } + } + } +} + extern "C" fn aero_ap_main(ap_id: usize) -> ! { log::info!("AP{}: Loaded userland", ap_id); diff --git a/src/aero_kernel/src/mem/alloc.rs b/src/aero_kernel/src/mem/alloc.rs index a5069f121fc..e5239d72c82 100644 --- a/src/aero_kernel/src/mem/alloc.rs +++ b/src/aero_kernel/src/mem/alloc.rs @@ -1,49 +1,73 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::alloc; use core::alloc::{GlobalAlloc, Layout}; -use super::paging::FRAME_ALLOCATOR; +use super::slab::{SlabHeader, SmallSlab}; use super::vmalloc; use crate::mem::paging::*; +use crate::utils::sync::IrqGuard; -struct Allocator {} +struct Allocator { + zones: [SmallSlab; 9], +} impl Allocator { const fn new() -> Self { - Self {} + Self { + zones: [ + SmallSlab::new(8), + SmallSlab::new(16), + SmallSlab::new(32), + SmallSlab::new(64), + SmallSlab::new(128), + SmallSlab::new(256), + SmallSlab::new(512), + SmallSlab::new(1024), + SmallSlab::new(2048), + ], + } } fn alloc(&self, layout: Layout) -> *mut u8 { + let _guard = IrqGuard::new(); + let size = align_up(layout.size() as _, layout.align() as _); - if size <= 4096 { - let frame: PhysFrame = FRAME_ALLOCATOR.allocate_frame().unwrap(); - frame.start_address().as_hhdm_virt().as_mut_ptr() + for slab in self.zones.iter() { + if size as usize <= slab.size() { + return slab.alloc(); + } + } + + if size <= Size2MiB::SIZE { + FRAME_ALLOCATOR + .alloc(size as usize) + .unwrap() + .as_hhdm_virt() + .as_mut_ptr() } else { let size = align_up(size, Size4KiB::SIZE) / Size4KiB::SIZE; vmalloc::get_vmalloc() .alloc(size as usize) .map(|addr| addr.as_mut_ptr::()) - .unwrap_or(core::ptr::null_mut()) + .unwrap() } } @@ -55,7 +79,11 @@ impl Allocator { return; } - // TODO: free the slab. + let _guard = IrqGuard::new(); + if layout.size() <= 1024 { + let slab_header = SlabHeader::from_object(ptr); + slab_header.as_slab().dealloc(ptr); + } } } @@ -182,12 +210,11 @@ unsafe impl GlobalAlloc for LockedHeap { // SAFETY: We we need to be careful to not cause a deadlock as the interrupt // handlers utilize the heap and might interrupt an in-progress allocation. So, we // lock the interrupts during the allocation. - let ptr = self.0.alloc(layout); #[cfg(feature = "kmemleak")] kmemleak::MEM_LEAK_CATCHER.track_caller(ptr, layout); - ptr + self.0.alloc(layout) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { diff --git a/src/aero_kernel/src/mem/mod.rs b/src/aero_kernel/src/mem/mod.rs index ed9ee17a821..f7eb4792567 100644 --- a/src/aero_kernel/src/mem/mod.rs +++ b/src/aero_kernel/src/mem/mod.rs @@ -1,34 +1,29 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . pub mod alloc; pub mod paging; pub mod pti; +mod slab; mod vmalloc; -use core::alloc::Layout; - use ::alloc::boxed::Box; -use crate::mem::paging::*; - -use self::paging::{active_level_4_table, FRAME_ALLOCATOR}; +use paging::*; /// Structure representing a *virtual* address space. The address space /// contains a reference of the page table allocated for this address space. @@ -84,9 +79,8 @@ impl AddressSpace { } let addr = PhysAddr::new(value & 0x_000f_ffff_ffff_f000); - let frame = PhysFrame::containing_address(addr); - frame + PhysFrame::containing_address(addr) }; Self { cr3 } @@ -122,7 +116,7 @@ impl AddressSpace { unsafe { &mut *(self.cr3.start_address().as_hhdm_virt().as_mut_ptr()) } } - /// Returns a mutable refernce to the mapper pointing to the page table + /// Returns a mutable reference to the mapper pointing to the page table /// allocated for this address space. pub fn offset_page_table(&mut self) -> OffsetPageTable { unsafe { OffsetPageTable::new(self.page_table(), crate::PHYSICAL_MEMORY_OFFSET) } @@ -130,13 +124,5 @@ impl AddressSpace { } pub fn alloc_boxed_buffer(size: usize) -> Box<[T]> { - if size == 0 { - return >::default(); - } - - let layout = unsafe { Layout::from_size_align_unchecked(size, 8) }; - let ptr = unsafe { ::alloc::alloc::alloc_zeroed(layout) as *mut T }; - let slice_ptr = core::ptr::slice_from_raw_parts_mut(ptr, size); - - unsafe { Box::from_raw(slice_ptr) } + unsafe { Box::new_zeroed_slice(size).assume_init() } } diff --git a/src/aero_kernel/src/mem/paging/addr.rs b/src/aero_kernel/src/mem/paging/addr.rs index 2b9b44d3151..b5193b30e63 100644 --- a/src/aero_kernel/src/mem/paging/addr.rs +++ b/src/aero_kernel/src/mem/paging/addr.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! Physical and virtual addresses manipulation @@ -23,6 +21,8 @@ use core::fmt; use core::iter::Step; use core::ops::{Add, AddAssign, Sub, SubAssign}; +use crate::fs::FileSystemError; + use super::page_table::{PageOffset, PageTableIndex}; use super::{PageSize, Size4KiB, VmFrame}; @@ -35,7 +35,7 @@ use bit_field::BitField; /// [`TryFrom`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html) trait can be used for performing conversions /// between `u64` and `usize`. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct VirtAddr(u64); @@ -52,14 +52,28 @@ pub struct VirtAddr(u64); #[repr(transparent)] pub struct PhysAddr(u64); -/// A passed `u64` was not a valid virtual address. -/// -/// This means that bits 48 to 64 are not -/// a valid sign extension and are not null either. So automatic sign extension would have -/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid -/// address calculation. -#[derive(Debug)] -pub struct VirtAddrNotValid(u64); +#[derive(Copy, Clone, Debug)] +pub enum ReadErr { + Null, + NotAligned, +} + +impl From for FileSystemError { + fn from(_: ReadErr) -> Self { + // `FileSystemError::NotSupported` will be converted to `EINVAL` on + // syscall error conversion. + FileSystemError::NotSupported + } +} + +impl From for aero_syscall::SyscallError { + fn from(value: ReadErr) -> Self { + match value { + ReadErr::Null => Self::EINVAL, + ReadErr::NotAligned => Self::EACCES, + } + } +} impl VirtAddr { /// Creates a new canonical virtual address. @@ -83,15 +97,33 @@ impl VirtAddr { /// Converts the address to a raw pointer. #[cfg(target_pointer_width = "64")] #[inline] - pub fn as_ptr(self) -> *const T { + pub const fn as_ptr(self) -> *const T { self.as_u64() as *const T } /// Converts the address to a mutable raw pointer. #[cfg(target_pointer_width = "64")] #[inline] - pub fn as_mut_ptr(self) -> *mut T { - self.as_ptr::() as *mut T + pub const fn as_mut_ptr(self) -> *mut T { + self.as_ptr::().cast_mut() + } + + #[inline] + pub const fn is_zero(self) -> bool { + self.0 == 0 + } + + pub fn is_canonical(self) -> bool { + let virtual_mask_shift = if super::level_5_paging_enabled() { + 56 + } else { + 47 + }; + + let shift = 64 - (virtual_mask_shift + 1); + + // By doing the right shift as a signed operation will sign extend the value. + ((self.as_u64() << shift) as i64 >> shift) as u64 == self.as_u64() } /// Validate reads `sizeof(T)` bytes from the virtual address and returns a mutable @@ -99,27 +131,35 @@ impl VirtAddr { /// /// ## Example /// ```no_run - /// let address: &mut SomeStruct = VirtAddr::new(0xcafebabe) - /// .read_mut::(); - /// .ok_or(AeroSyscallError::EFAULT)?; + /// let address: &mut SomeStruct = VirtAddr::new(0xcafebabe).read_mut::()?; /// ``` - pub fn read_mut<'struc, T: Sized>(&self) -> Option<&'struc mut T> { - if self.validate_read::() { - Some(unsafe { &mut *(self.as_mut_ptr() as *mut T) }) - } else { - None - } + pub fn read_mut<'a, T: Sized>(&self) -> Result<&'a mut T, ReadErr> { + self.validate_read::()?; + Ok(unsafe { &mut *self.as_mut_ptr() }) + } + + pub fn as_bytes_mut<'a>(&self, size_bytes: usize) -> &'a mut [u8] { + self.validate_read::<&[u8]>().unwrap(); + unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), size_bytes) } } /// Converts this HHDM (Higher Half Direct Map) virtual address to its physical address. pub fn as_hhdm_phys(&self) -> PhysAddr { - unsafe { PhysAddr::new(self.clone() - crate::PHYSICAL_MEMORY_OFFSET) } + unsafe { PhysAddr::new(*self - crate::PHYSICAL_MEMORY_OFFSET) } } /// Returns if the address is valid to read `sizeof(T)` bytes at the address. - fn validate_read(&self) -> bool { - // FIXME: (*self + core::mem::size_of::()) <= crate::arch::task::userland_last_address() // in-range - self.0 != 0 // non-null + fn validate_read(&self) -> Result<(), ReadErr> { + // FIXME: (*self + core::mem::size_of::()) <= crate::arch::task::userland_last_address() + let raw = self.as_ptr::(); + + if raw.is_null() { + return Err(ReadErr::Null); + } else if !raw.is_aligned() { + return Err(ReadErr::NotAligned); + } + + Ok(()) } /// Aligns the virtual address downwards to the given alignment. @@ -237,6 +277,7 @@ impl fmt::Pointer for VirtAddr { impl Add for VirtAddr { type Output = Self; + #[inline] fn add(self, rhs: u64) -> Self::Output { VirtAddr::new(self.0 + rhs) @@ -253,6 +294,7 @@ impl AddAssign for VirtAddr { #[cfg(target_pointer_width = "64")] impl Add for VirtAddr { type Output = Self; + #[inline] fn add(self, rhs: usize) -> Self::Output { self + rhs as u64 @@ -269,6 +311,7 @@ impl AddAssign for VirtAddr { impl Sub for VirtAddr { type Output = Self; + #[inline] fn sub(self, rhs: u64) -> Self::Output { VirtAddr::new(self.0.checked_sub(rhs).unwrap()) @@ -285,6 +328,7 @@ impl SubAssign for VirtAddr { #[cfg(target_pointer_width = "64")] impl Sub for VirtAddr { type Output = Self; + #[inline] fn sub(self, rhs: usize) -> Self::Output { self - rhs as u64 @@ -301,6 +345,7 @@ impl SubAssign for VirtAddr { impl Sub for VirtAddr { type Output = u64; + #[inline] fn sub(self, rhs: VirtAddr) -> Self::Output { self.as_u64().checked_sub(rhs.as_u64()).unwrap() @@ -309,11 +354,12 @@ impl Sub for VirtAddr { impl Step for VirtAddr { #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { if start < end { - Some((end.as_u64() - start.as_u64()) as _) + let n = (end.as_u64() - start.as_u64()) as usize; + (n, Some(n)) } else { - None + (0, None) } } @@ -328,12 +374,6 @@ impl Step for VirtAddr { } } -/// A passed `u64` was not a valid physical address. -/// -/// This means that bits 52 to 64 were not all null. -#[derive(Debug)] -pub struct PhysAddrNotValid(u64); - impl PhysAddr { /// Creates a new physical address. /// @@ -454,6 +494,7 @@ impl fmt::Pointer for PhysAddr { impl Add for PhysAddr { type Output = Self; + fn add(self, rhs: u64) -> Self::Output { PhysAddr::new(self.0 + rhs) } @@ -468,6 +509,7 @@ impl AddAssign for PhysAddr { #[cfg(target_pointer_width = "64")] impl Add for PhysAddr { type Output = Self; + fn add(self, rhs: usize) -> Self::Output { self + rhs as u64 } @@ -482,6 +524,7 @@ impl AddAssign for PhysAddr { impl Sub for PhysAddr { type Output = Self; + fn sub(self, rhs: u64) -> Self::Output { PhysAddr::new(self.0.checked_sub(rhs).unwrap()) } @@ -496,6 +539,7 @@ impl SubAssign for PhysAddr { #[cfg(target_pointer_width = "64")] impl Sub for PhysAddr { type Output = Self; + #[inline] fn sub(self, rhs: usize) -> Self::Output { self - rhs as u64 @@ -511,6 +555,7 @@ impl SubAssign for PhysAddr { impl Sub for PhysAddr { type Output = u64; + fn sub(self, rhs: PhysAddr) -> Self::Output { self.as_u64().checked_sub(rhs.as_u64()).unwrap() } @@ -533,7 +578,7 @@ pub fn align_down(addr: u64, align: u64) -> u64 { /// Panics if the alignment is not a power of two. Without the `const_fn` /// feature, the panic message will be "index out of bounds". #[inline] -pub fn align_up(addr: u64, align: u64) -> u64 { +pub const fn align_up(addr: u64, align: u64) -> u64 { let align_mask = align - 1; if addr & align_mask == 0 { @@ -544,7 +589,7 @@ pub fn align_up(addr: u64, align: u64) -> u64 { } #[inline] -pub fn is_aligned(addr: u64, align: u64) -> bool { +pub const fn is_aligned(addr: u64, align: u64) -> bool { align_up(addr, align) == addr } diff --git a/src/aero_kernel/src/mem/paging/frame.rs b/src/aero_kernel/src/mem/paging/frame.rs index 827cdfc3a50..b12b81d9d46 100644 --- a/src/aero_kernel/src/mem/paging/frame.rs +++ b/src/aero_kernel/src/mem/paging/frame.rs @@ -1,28 +1,27 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::alloc::{AllocError, Allocator, Layout}; use core::ptr::NonNull; use core::sync::atomic::{AtomicUsize, Ordering}; use alloc::vec::Vec; -use limine::{LimineMemmapEntry, LimineMemoryMapEntryType, NonNullPtr}; + +use limine::memory_map; use spin::Once; use super::mapper::*; @@ -34,90 +33,121 @@ use crate::mem::paging::align_up; use crate::utils::bitmap::Bitmap; use crate::utils::sync::Mutex; -static BUDDY_SIZE: [u64; 3] = [Size4KiB::SIZE, Size4KiB::SIZE * 4, Size2MiB::SIZE]; +const BUDDY_SIZE: [u64; 10] = [ + Size4KiB::SIZE, // 4 KiB + Size4KiB::SIZE * 2, // 8 KiB + Size4KiB::SIZE * 4, // 16 KiB + Size4KiB::SIZE * 8, // 32 KiB + Size4KiB::SIZE * 16, // 64 KiB + Size4KiB::SIZE * 32, // 128 KiB + Size4KiB::SIZE * 64, // 256 KiB + Size4KiB::SIZE * 128, // 512 KiB + Size4KiB::SIZE * 256, // 1 MiB + Size2MiB::SIZE, // 2 MiB +]; + +const fn order_from_size(size: u64) -> usize { + // UNSTABLE: We cannot make an iterator from `BUDDY_SIZE` or use a for loop + // in const context. + let mut order = 0; + + while order < BUDDY_SIZE.len() { + let buddy_size = BUDDY_SIZE[order]; + if buddy_size >= size { + return order; + } + + order += 1; + } + + unreachable!() +} -pub struct LockedFrameAllocator(Once>); +pub struct LockedFrameAllocator(Mutex); impl LockedFrameAllocator { /// Constructs a new uninitialized and locked version of the global frame /// allocator. pub(super) const fn new_uninit() -> Self { - Self(Once::new()) + let bstrap_ref = BootAllocRef { + inner: core::ptr::null(), + }; + + Self(Mutex::new(GlobalFrameAllocator { + buddies: [ + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + Bitmap::empty(bstrap_ref), + ], + free: [0; 10], + + base: PhysAddr::zero(), + end: PhysAddr::zero(), + })) } /// Initializes the inner locked global frame allocator. - pub(super) fn init(&self, memory_map: &mut [NonNullPtr]) { - self.0 - .call_once(|| Mutex::new(GlobalFrameAllocator::new(memory_map))); + pub(super) fn init(&self, memory_map: &mut limine::response::MemoryMapResponse) { + *self.0.lock_irq() = GlobalFrameAllocator::new(memory_map); + } + + pub fn dealloc(&self, addr: PhysAddr, size_bytes: usize) { + let order = order_from_size(size_bytes as u64); + + let mut allocator = self.0.lock_irq(); + allocator.deallocate_frame_inner(addr, order); + } + + pub fn alloc(&self, size_bytes: usize) -> Option { + let order = order_from_size(size_bytes as u64); + + let mut allocator = self.0.lock_irq(); + allocator.allocate_frame_inner(order) + } + + pub fn alloc_zeroed(&self, size_bytes: usize) -> Option { + let addr = self.alloc(size_bytes)?; + addr.as_hhdm_virt().as_bytes_mut(size_bytes).fill(0); + + Some(addr) } } unsafe impl FrameAllocator for LockedFrameAllocator { - #[track_caller] fn allocate_frame(&self) -> Option> { - // let caller = core::panic::Location::caller(); - // log::debug!("allocation request of 4KiB by {:?}", caller); - - self.0 - .get() - .map(|m| { - m.lock() - .allocate_frame_inner(0) - .map(|f| PhysFrame::containing_address(f)) - }) - .unwrap_or(None) - .map(|frame| { - frame.as_slice_mut().fill(0); - frame - }) + let phys = self.alloc(Size4KiB::SIZE as _)?; + Some(PhysFrame::containing_address(phys)) } - #[track_caller] fn deallocate_frame(&self, frame: PhysFrame) { - // let caller = core::panic::Location::caller(); - // log::debug!("deallocation request of 4KiB by {:?}", caller); - - // self.0 - // .get() - // .map(|m| m.lock().deallocate_frame_inner(frame.start_address(), 0)) - // .unwrap_or(()); + self.0 + .lock_irq() + .deallocate_frame_inner(frame.start_address(), order_from_size(Size4KiB::SIZE)) } } unsafe impl FrameAllocator for LockedFrameAllocator { - #[track_caller] fn allocate_frame(&self) -> Option> { - // let caller = core::panic::Location::caller(); - // log::debug!("allocation request of 2MiB by {:?}", caller); - - self.0 - .get() - .map(|m| { - m.lock() - .allocate_frame_inner(2) - .map(|f| PhysFrame::containing_address(f)) - }) - .unwrap_or(None) - .map(|frame| { - frame.as_slice_mut().fill(0); - frame - }) + let phys = self.alloc(Size2MiB::SIZE as _)?; + Some(PhysFrame::containing_address(phys)) } - #[track_caller] fn deallocate_frame(&self, frame: PhysFrame) { - // let caller = core::panic::Location::caller(); - // log::debug!("deallocation request of 2MiB by {:?}", caller); - self.0 - .get() - .map(|m| m.lock().deallocate_frame_inner(frame.start_address(), 2)) - .unwrap_or(()); + .lock_irq() + .deallocate_frame_inner(frame.start_address(), order_from_size(Size2MiB::SIZE)) } } struct RangeMemoryIter<'a> { - iter: core::slice::Iter<'a, NonNullPtr>, + iter: core::slice::Iter<'a, &'a memory_map::Entry>, cursor_base: PhysAddr, cursor_end: PhysAddr, @@ -129,16 +159,16 @@ impl<'a> Iterator for RangeMemoryIter<'a> { fn next(&mut self) -> Option { if self.cursor_base >= self.cursor_end { if let Some(entry) = loop { - // We need to find out the next useable memory range from + // We need to find out the next usable memory range from // the memory map and set the cursor to the start of it. let next = self.iter.next()?; - if next.typ == LimineMemoryMapEntryType::Usable { + if next.entry_type == memory_map::EntryType::USABLE { break Some(next); } } { self.cursor_base = PhysAddr::new(entry.base).align_up(Size4KiB::SIZE); - self.cursor_end = PhysAddr::new(entry.base + entry.len); + self.cursor_end = PhysAddr::new(entry.base + entry.length); } else { // We reached the end of the memory map. return None; @@ -161,30 +191,17 @@ impl<'a> Iterator for RangeMemoryIter<'a> { #[repr(usize)] pub enum BuddyOrdering { Size4KiB = 0, - Size8KiB = 2, + Size8KiB = 1, } +// FIXME: REMOVE THIS FUNCTION pub fn pmm_alloc(order: BuddyOrdering) -> PhysAddr { let order = order as usize; debug_assert!(order <= BUDDY_SIZE.len()); - let addr = super::FRAME_ALLOCATOR - .0 - .get() - .expect("pmm: frame allocator not initialized") - .lock() - .allocate_frame_inner(order) - .expect("pmm: out of memory"); - - let virt = addr.as_hhdm_virt(); - - let fill_size = BUDDY_SIZE[order] as usize; - let slice = unsafe { core::slice::from_raw_parts_mut(virt.as_mut_ptr::(), fill_size) }; - - // We always zero out memory for security reasons. - slice.fill(0x00); - - addr + super::FRAME_ALLOCATOR + .alloc(BUDDY_SIZE[order] as _) + .unwrap() } #[derive(Debug)] @@ -227,13 +244,13 @@ impl BootAlloc { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] struct BootAllocRef { inner: *const BootAlloc, } impl BootAllocRef { - fn new(inner: &BootAlloc) -> Self { + const fn new(inner: &BootAlloc) -> Self { Self { inner: inner as *const _, } @@ -265,70 +282,57 @@ unsafe impl Send for BootAllocRef {} static VM_FRAMES: Once> = Once::new(); -/// Buddy allocator combines power-of-two allocator with free buffer -/// coalescing. +/// Buddy allocator combines power-of-two allocator with free buffer coalescing. /// /// ## Overview /// /// Overview of the buddy allocation algorithm: /// -/// * Memory is broken up into large blocks of pages where each block -/// is a power of two number of pages. +/// * Memory is broken up into large blocks of pages where each block is a power of two number of +/// pages. /// -/// * If a block of the desired size is not available, a larger block is -/// broken up in half and the two blocks are marked as buddies then one half -/// is used for the allocation and the other half is marked free. +/// * If a block of the desired size is not available, a larger block is broken up in half and the +/// two blocks are marked as buddies then one half is used for the allocation and the other half +/// is marked free. /// -/// * The blocks are continuously halved as necessary until a block of the -/// desired size is available. +/// * The blocks are continuously halved as necessary until a block of the desired size is +/// available. /// -/// * When a block is later freed, the buddy is examined and the two coalesced -/// if it is free. +/// * When a block is later freed, the buddy is examined and the two coalesced if it is free. pub struct GlobalFrameAllocator { - buddies: [Bitmap; 3], - free: [usize; 3], + buddies: [Bitmap; 10], + free: [usize; 10], base: PhysAddr, end: PhysAddr, } impl GlobalFrameAllocator { - /// Create a new global frame allocator from the memory map provided by the bootloader. - fn new(memory_map: &mut [NonNullPtr]) -> Self { - // Find a memory map entry that is big enough to fit all of the items in - // range memory iter. - let requested_size = (core::mem::size_of::() * memory_map.len()) as u64; - let mut region = None; - - for i in 0..memory_map.len() { - let entry = &mut memory_map[i]; + fn new(memory_map_resp: &mut limine::response::MemoryMapResponse) -> Self { + let memory_map = memory_map_resp.entries_mut(); - // Make sure that the memory map entry is marked as usable. - if entry.typ != LimineMemoryMapEntryType::Usable { - continue; - } - - // Found a big enough memory map entry. - if entry.len >= requested_size { - let base = entry.base; + let requested_size = (core::mem::size_of::() * memory_map.len()) as u64; - entry.base += requested_size; - entry.len -= requested_size; + let entry = memory_map + .iter_mut() + .find(|entry| { + entry.entry_type == memory_map::EntryType::USABLE && entry.length >= requested_size + }) + .expect("OOM"); - region = Some(PhysAddr::new(base)); + let region = PhysAddr::new(entry.base); - break; - } - } + entry.base += requested_size; + entry.length -= requested_size; - let mut iter = memory_map.iter(); + let mut iter = memory_map_resp.entries().iter(); let cursor = iter .next() .expect("stivale2: unexpected end of the memory map"); let ranges = unsafe { - let virt_addr = region.expect("stivale2: out of memory").as_hhdm_virt(); + let virt_addr = region.as_hhdm_virt(); core::slice::from_raw_parts_mut::( virt_addr.as_mut_ptr(), @@ -340,11 +344,11 @@ impl GlobalFrameAllocator { iter, cursor_base: PhysAddr::new(cursor.base), - cursor_end: PhysAddr::new(cursor.base + cursor.len), + cursor_end: PhysAddr::new(cursor.base + cursor.length), }; // Lets goo! Now lets initialize the bootstrap allocator so we can initialize - // our efficient buddy allocator. We need a seperate allocator since some computers + // our efficient buddy allocator. We need a separate allocator since some computers // such as Macs have a shitload of memory map entries so, we cannt assume the amount // of maximum mmap entries and allocate space for it on the stack instead. God damn it. let mut i = 0; @@ -365,11 +369,18 @@ impl GlobalFrameAllocator { end, buddies: [ - Bitmap::empty(bref.clone()), - Bitmap::empty(bref.clone()), - Bitmap::empty(bref.clone()), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), + Bitmap::empty(bref), ], - free: [0; 3], + free: [0; 10], }; let size = this.end - this.base; @@ -377,7 +388,7 @@ impl GlobalFrameAllocator { // Allocate the buddies using prealloc: for (i, bsize) in BUDDY_SIZE.iter().enumerate() { let chunk = size / bsize; - this.buddies[i] = Bitmap::new_in(bref.clone(), chunk as usize); + this.buddies[i] = Bitmap::new_in(bref, chunk as usize); } for region in bref.get_inner().memory_ranges.lock().iter() { @@ -407,12 +418,12 @@ impl GlobalFrameAllocator { if mask & address.as_u64() != 0 { continue; - } else { - return order; } + + return order; } - return 0; + 0 } fn get_bit_idx(&self, addr: PhysAddr, order: usize) -> usize { @@ -444,17 +455,17 @@ impl GlobalFrameAllocator { /// Inserts the provided memory range. fn insert_range(&mut self, base: PhysAddr, end: PhysAddr) { - let mut remaning = end - base; + let mut remaining = end - base; let mut current = base; - while remaning > 0 { - let order = self.find_order(current, remaning); + while remaining > 0 { + let order = self.find_order(current, remaining); let size = BUDDY_SIZE[order]; self.set_bit(current, order); current += size; - remaning -= size; + remaining -= size; } } @@ -473,7 +484,7 @@ impl GlobalFrameAllocator { let idx = self.get_bit_idx(addr, order); let buddy = &mut self.buddies[order]; - let change = buddy.is_set(idx) == true; + let change = buddy.is_set(idx); if change { buddy.set(idx, false); @@ -523,15 +534,15 @@ impl GlobalFrameAllocator { if self.free[i] > 0 { let result = self.find_free(i)?; - let mut remaning = bsize - size; + let mut remaining = bsize - size; - if remaning > 0 { + if remaining > 0 { for j in (0..=i).rev() { let sizee = BUDDY_SIZE[j]; - while remaning >= sizee { - self.set_bit(result + (remaning - sizee) + size, j); - remaning -= sizee; + while remaining >= sizee { + self.set_bit(result + (remaining - sizee) + size, j); + remaining -= sizee; } } } @@ -546,12 +557,7 @@ impl GlobalFrameAllocator { pub fn init_vm_frames() { VM_FRAMES.call_once(|| { - let frame_count = super::FRAME_ALLOCATOR - .0 - .get() - .unwrap() - .lock_irq() - .frame_count(); + let frame_count = super::FRAME_ALLOCATOR.0.lock_irq().frame_count(); let mut frames = Vec::::new(); frames.resize_with(frame_count, VmFrame::new); diff --git a/src/aero_kernel/src/mem/paging/mapper.rs b/src/aero_kernel/src/mem/paging/mapper.rs index ec9fbdac41b..2c218a5e5d3 100644 --- a/src/aero_kernel/src/mem/paging/mapper.rs +++ b/src/aero_kernel/src/mem/paging/mapper.rs @@ -1,36 +1,29 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . // Some code borrowed from the x86_64 crate (MIT + Apache) and add support for 5-level paging // and some kernel specific features that cannot be directly done in the crate itself. -use core::ops::Range; +use core::ops::{Range, RangeInclusive}; -use crate::mem::AddressSpace; - -use super::{ - addr::{PhysAddr, VirtAddr}, - page::PhysFrame, - page::{AddressNotAligned, Page, PageSize, Size1GiB, Size2MiB, Size4KiB}, - page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}, - FRAME_ALLOCATOR, -}; +use super::addr::{PhysAddr, VirtAddr}; +use super::page::{AddressNotAligned, Page, PageSize, PhysFrame, Size1GiB, Size2MiB, Size4KiB}; +use super::page_table::{FrameError, PageTable, PageTableEntry, PageTableFlags}; +use super::FRAME_ALLOCATOR; /// A trait for types that can allocate a frame of memory. /// @@ -83,7 +76,7 @@ pub enum TranslateResult { Mapped { /// The mapped frame. frame: MappedFrame, - /// The offset whithin the mapped frame. + /// The offset within the mapped frame. offset: u64, /// The entry flags in the lowest-level page table. /// @@ -137,12 +130,13 @@ pub trait Mapper { /// This function might need additional physical frames to create new page tables. These /// frames are allocated from the `allocator` argument. At most three frames are required. /// - /// Parent page table entries are automatically updated with `PRESENT | WRITABLE | USER_ACCESSIBLE` - /// if present in the `PageTableFlags`. Depending on the used mapper implementation - /// the `PRESENT` and `WRITABLE` flags might be set for parent tables, + /// Parent page table entries are automatically updated with `PRESENT | WRITABLE | + /// USER_ACCESSIBLE` if present in the `PageTableFlags`. Depending on the used mapper + /// implementation the `PRESENT` and `WRITABLE` flags might be set for parent tables, /// even if they are not set in `PageTableFlags`. /// - /// The `map_to_with_table_flags` method gives explicit control over the parent page table flags. + /// The `map_to_with_table_flags` method gives explicit control over the parent page table + /// flags. /// /// ## Safety /// @@ -156,16 +150,16 @@ pub trait Mapper { /// violations can occur through the new mapping. Among other things, the /// caller must prevent the following: /// - /// - Aliasing of `&mut` references, i.e. two `&mut` references that point to - /// the same physical address. This is undefined behavior in Rust. - /// - This can be ensured by mapping each page to an individual physical - /// frame that is not mapped anywhere else. - /// - Creating uninitalized or invalid values: Rust requires that all values - /// have a correct memory layout. For example, a `bool` must be either a 0 - /// or a 1 in memory, but not a 3 or 4. An exception is the `MaybeUninit` - /// wrapper type, which abstracts over possibly uninitialized memory. - /// - This is only a problem when re-mapping pages to different physical - /// frames. Mapping a page that is not in use yet is fine. + /// - Aliasing of `&mut` references, i.e. two `&mut` references that point to the same physical + /// address. This is undefined behavior in Rust. + /// - This can be ensured by mapping each page to an individual physical frame that is not + /// mapped anywhere else. + /// - Creating uninitialized or invalid values: Rust requires that all values have a correct + /// memory layout. For example, a `bool` must be either a 0 or a 1 in memory, but not a 3 or + /// 4. An exception is the `MaybeUninit` wrapper type, which abstracts over possibly + /// uninitialized memory. + /// - This is only a problem when re-mapping pages to different physical frames. Mapping a + /// page that is not in use yet is fine. /// /// Special care must be taken when sharing pages with other address spaces, /// e.g. by setting the `GLOBAL` flag. For example, a global mapping must be @@ -210,16 +204,16 @@ pub trait Mapper { /// violations can occur through the new mapping. Among other things, the /// caller must prevent the following: /// - /// - Aliasing of `&mut` references, i.e. two `&mut` references that point to - /// the same physical address. This is undefined behavior in Rust. - /// - This can be ensured by mapping each page to an individual physical - /// frame that is not mapped anywhere else. - /// - Creating uninitalized or invalid values: Rust requires that all values - /// have a correct memory layout. For example, a `bool` must be either a 0 - /// or a 1 in memory, but not a 3 or 4. An exception is the `MaybeUninit` - /// wrapper type, which abstracts over possibly uninitialized memory. - /// - This is only a problem when re-mapping pages to different physical - /// frames. Mapping a page that is not in use yet is fine. + /// - Aliasing of `&mut` references, i.e. two `&mut` references that point to the same physical + /// address. This is undefined behavior in Rust. + /// - This can be ensured by mapping each page to an individual physical frame that is not + /// mapped anywhere else. + /// - Creating uninitialized or invalid values: Rust requires that all values have a correct + /// memory layout. For example, a `bool` must be either a 0 or a 1 in memory, but not a 3 or + /// 4. An exception is the `MaybeUninit` wrapper type, which abstracts over possibly + /// uninitialized memory. + /// - This is only a problem when re-mapping pages to different physical frames. Mapping a + /// page that is not in use yet is fine. /// /// Special care must be taken when sharing pages with other address spaces, /// e.g. by setting the `GLOBAL` flag. For example, a global mapping must be @@ -390,10 +384,10 @@ impl<'a, P: PageTableFrameMapping> MappedPageTable<'a, P> { /// /// ## Safety /// - /// This function is unsafe because the caller must guarantee that the passed `page_table_frame_mapping` - /// closure is correct. Also, the passed `page_table` must point to the level 4 page table - /// of a valid page table hierarchy. Otherwise this function might break memory safety, e.g. - /// by writing to an illegal memory location. + /// This function is unsafe because the caller must guarantee that the passed + /// `page_table_frame_mapping` closure is correct. Also, the passed `page_table` must point + /// to the level 4 page table of a valid page table hierarchy. Otherwise this function might + /// break memory safety, e.g. by writing to an illegal memory location. #[inline] pub unsafe fn new(page_table: &'a mut PageTable, page_table_frame_mapping: P) -> Self { Self { @@ -534,17 +528,14 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { &mut self, page: Page, ) -> Result<(PhysFrame, MapperFlush), UnmapError> { - let p4; - - if self.level_5_paging_enabled { + let p4 = if self.level_5_paging_enabled { let p5 = &mut self.page_table; - p4 = self - .page_table_walker - .next_table_mut(&mut p5[page.p5_index()])?; + self.page_table_walker + .next_table_mut(&mut p5[page.p5_index()])? } else { - p4 = &mut self.page_table; - } + &mut self.page_table + }; let p3 = self .page_table_walker @@ -577,17 +568,14 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { page: Page, flags: PageTableFlags, ) -> Result, FlagUpdateError> { - let p4; - - if self.level_5_paging_enabled { + let p4 = if self.level_5_paging_enabled { let p5 = &mut self.page_table; - p4 = self - .page_table_walker - .next_table_mut(&mut p5[page.p5_index()])?; + self.page_table_walker + .next_table_mut(&mut p5[page.p5_index()])? } else { - p4 = &mut self.page_table; - } + &mut self.page_table + }; let p3 = self .page_table_walker @@ -613,7 +601,7 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { p4 = self.page_table_walker.next_table(&p5[page.p5_index()])?; } else { - p4 = &self.page_table; + p4 = self.page_table; } let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; @@ -686,17 +674,14 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { page: Page, flags: PageTableFlags, ) -> Result, FlagUpdateError> { - let p4; - - if self.level_5_paging_enabled { + let p4 = if self.level_5_paging_enabled { let p5 = &mut self.page_table; - p4 = self - .page_table_walker - .next_table_mut(&mut p5[page.p5_index()])?; + self.page_table_walker + .next_table_mut(&mut p5[page.p5_index()])? } else { - p4 = &mut self.page_table; - } + &mut self.page_table + }; let p3 = self .page_table_walker @@ -725,7 +710,7 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { p4 = self.page_table_walker.next_table(&p5[page.p5_index()])?; } else { - p4 = &self.page_table; + p4 = self.page_table; } let p3 = self.page_table_walker.next_table(&p4[page.p4_index()])?; @@ -759,7 +744,7 @@ impl<'a, P: PageTableFrameMapping> Translate for MappedPageTable<'a, P> { } }; } else { - p4 = &self.page_table; + p4 = self.page_table; } let p3 = match self.page_table_walker.next_table(&p4[addr.p4_index()]) { @@ -775,7 +760,7 @@ impl<'a, P: PageTableFrameMapping> Translate for MappedPageTable<'a, P> { Err(PageTableWalkError::MappedToHugePage) => { let entry = &p3[addr.p3_index()]; let frame = PhysFrame::containing_address(entry.addr()); - let offset = addr.as_u64() & 0o_777_777_7777; + let offset = addr.as_u64() & 0o7_777_777_777; let flags = entry.flags(); return TranslateResult::Mapped { frame: MappedFrame::Size1GiB(frame), @@ -790,7 +775,7 @@ impl<'a, P: PageTableFrameMapping> Translate for MappedPageTable<'a, P> { Err(PageTableWalkError::MappedToHugePage) => { let entry = &p2[addr.p2_index()]; let frame = PhysFrame::containing_address(entry.addr()); - let offset = addr.as_u64() & 0o_777_7777; + let offset = addr.as_u64() & 0o7_777_777; let flags = entry.flags(); return TranslateResult::Mapped { frame: MappedFrame::Size2MiB(frame), @@ -1143,195 +1128,53 @@ impl<'a> Translate for OffsetPageTable<'a> { } impl<'a> OffsetPageTable<'a> { - pub fn unmap_range(&mut self, range: Range, step: u64) -> Result<(), UnmapError> { - for addr in range.step_by(step as usize) { - let page: Page = Page::containing_address(addr); - self.inner.unmap(page)?.1.flush(); - } - - Ok(()) - } - - pub fn fork(&mut self) -> Result> { - let mut address_space = AddressSpace::new()?; // Allocate the new address space - - let offset_table = address_space.offset_page_table(); - let make_next_level = |table: &mut PageTable, - i: usize| - -> Result<(bool, &mut PageTable), MapToError> { - let entry = &mut table[i]; - let created; - - if !entry.flags().contains(PageTableFlags::PRESENT) { - let frame = FRAME_ALLOCATOR - .allocate_frame() - .ok_or(MapToError::FrameAllocationFailed)?; - - entry.set_frame( - frame, - PageTableFlags::PRESENT - | PageTableFlags::WRITABLE - | PageTableFlags::USER_ACCESSIBLE, - ); - - created = true; - } else { - entry.set_flags( - PageTableFlags::PRESENT - | PageTableFlags::WRITABLE - | PageTableFlags::USER_ACCESSIBLE, - ); - - created = false; - } - - let page_table_ptr = { - let addr = entry.frame().unwrap().start_address().as_hhdm_virt(); - addr.as_mut_ptr::() - }; - - let page_table: &mut PageTable = unsafe { &mut *page_table_ptr }; - if created { - page_table.zero(); + pub fn copy_page_range(&mut self, src: &mut OffsetPageTable, range: RangeInclusive) { + let mut map_to = |src: &mut OffsetPageTable, addr, frame, flags| match frame { + MappedFrame::Size4KiB(frame) => { + let page = Page::::containing_address(addr); + + unsafe { + self.map_to_with_table_flags( + page, + frame, + flags, + PageTableFlags::PRESENT + | PageTableFlags::USER_ACCESSIBLE + | PageTableFlags::WRITABLE, + ) + } + .unwrap() + // operating on an inactive page table + .ignore(); + + unsafe { src.update_flags(page, flags) } + .unwrap() + // caller is required to invalidate the TLB + .ignore(); } - - Ok((created, page_table)) + _ => todo!(), }; - let last_level_fork = |entry: &mut PageTableEntry, n1: &mut PageTable, i: usize| { - let mut flags = entry.flags(); + let mut addr = *range.start(); - // Setup copy on write page. - flags.remove(PageTableFlags::WRITABLE); + while addr != *range.end() { + match src.translate(addr) { + TranslateResult::Mapped { + frame, + offset, + flags, + } => { + assert_eq!(offset, 0, "unaligned page range"); + map_to(src, addr, frame, flags & !PageTableFlags::WRITABLE); + } - entry.set_flags(flags); - n1[i].set_frame(entry.frame().unwrap(), flags); - }; + TranslateResult::NotMapped => {} + TranslateResult::InvalidFrameAddress(addr) => { + panic!("invalid frame address {:#x}", addr); + } + } - // We loop through each of the page table entries in the page table which are user - // accessable and we remove the writeable flag from the entry if present. This will - // make the page table entry copy on the first write. Then we clone the page table entry - // and place it in the new page table. - if self.inner.level_5_paging_enabled { - self.inner.page_table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |i, _, table| { - let (_, n4) = make_next_level(offset_table.inner.page_table, i)?; - let mut count_4 = 0; - - table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |j, _, table| { - let (w3, n3) = make_next_level(n4, j)?; - let mut count_3 = 0; - - if w3 { - count_4 += 1; - } - - table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |k, _, table| { - let (w2, n2) = make_next_level(n3, k)?; - let mut count_2 = 0; - - if w2 { - count_3 += 1; - } - - table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |l, _, table| { - let (w1, n1) = make_next_level(n2, l)?; - let mut count_1 = 0; - - if w1 { - count_2 += 1; - } - - table.for_entries_mut( - PageTableFlags::PRESENT - | PageTableFlags::USER_ACCESSIBLE, - |i, entry, _| { - last_level_fork(entry, n1, i); - - count_1 += 1; - Ok(()) - }, - )?; - - n2[l].set_entry_count(count_1); - Ok(()) - }, - )?; - - n3[k].set_entry_count(count_2); - Ok(()) - }, - )?; - - n4[j].set_entry_count(count_3); - Ok(()) - }, - )?; - - offset_table.inner.page_table[i].set_entry_count(count_4); - Ok(()) - }, - )?; - } else { - self.inner.page_table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |i, _, table| { - let (_, n3) = make_next_level(offset_table.inner.page_table, i)?; - let mut count_3 = 0; - - table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |k, _, table| { - let (w2, n2) = make_next_level(n3, k)?; - let mut count_2 = 0; - - if w2 { - count_3 += 1; - } - - table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |l, _, table| { - let (w1, n1) = make_next_level(n2, l)?; - let mut count_1 = 0; - - if w1 { - count_2 += 1; - } - - table.for_entries_mut( - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE, - |i, entry, _| { - last_level_fork(entry, n1, i); - - count_1 += 1; - Ok(()) - }, - )?; - - n2[l].set_entry_count(count_1); - Ok(()) - }, - )?; - - n3[k].set_entry_count(count_2); - Ok(()) - }, - )?; - - offset_table.inner.page_table[i].set_entry_count(count_3); - Ok(()) - }, - )?; + addr += Size4KiB::SIZE; } - - Ok(address_space) } } diff --git a/src/aero_kernel/src/mem/paging/mod.rs b/src/aero_kernel/src/mem/paging/mod.rs index 0fbe6a07d1a..7e523182dbd 100644 --- a/src/aero_kernel/src/mem/paging/mod.rs +++ b/src/aero_kernel/src/mem/paging/mod.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . mod addr; mod frame; @@ -25,22 +23,17 @@ mod page_table; pub use self::addr::*; pub use self::frame::*; -pub use self::mapper::MapperFlush; pub use self::mapper::*; pub use self::page::*; pub use self::page_table::*; -use limine::LimineMemmapEntry; -use limine::NonNullPtr; - -pub use frame::LockedFrameAllocator; - use crate::PHYSICAL_MEMORY_OFFSET; pub static FRAME_ALLOCATOR: LockedFrameAllocator = LockedFrameAllocator::new_uninit(); bitflags::bitflags! { /// Describes an page fault error code. + #[derive(Debug, Copy, Clone)] #[repr(transparent)] pub struct PageFaultErrorCode: u64 { /// If this flag is set, the page fault was caused by a page-protection violation, @@ -81,12 +74,12 @@ pub const fn level_5_paging_enabled() -> bool { /// Initialize paging. pub fn init( - memory_regions: &mut [NonNullPtr], + mmap_resp: &mut limine::response::MemoryMapResponse, ) -> Result, MapToError> { let active_level_4 = unsafe { active_level_4_table() }; let offset_table = unsafe { OffsetPageTable::new(active_level_4, PHYSICAL_MEMORY_OFFSET) }; - FRAME_ALLOCATOR.init(memory_regions); + FRAME_ALLOCATOR.init(mmap_resp); Ok(offset_table) } diff --git a/src/aero_kernel/src/mem/paging/page.rs b/src/aero_kernel/src/mem/paging/page.rs index e70a635ce85..84894fea5b5 100644 --- a/src/aero_kernel/src/mem/paging/page.rs +++ b/src/aero_kernel/src/mem/paging/page.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! Abstractions for default-sized and huge virtual memory pages. @@ -148,6 +146,7 @@ impl fmt::Debug for Page { impl Add for Page { type Output = Self; + #[inline] fn add(self, rhs: u64) -> Self::Output { Page::containing_address(self.start_address() + rhs * S::SIZE) @@ -163,6 +162,7 @@ impl AddAssign for Page { impl Sub for Page { type Output = Self; + #[inline] fn sub(self, rhs: u64) -> Self::Output { Page::containing_address(self.start_address() - rhs * S::SIZE) @@ -178,6 +178,7 @@ impl SubAssign for Page { impl Sub for Page { type Output = u64; + #[inline] fn sub(self, rhs: Self) -> Self::Output { (self.start_address - rhs.start_address) / S::SIZE @@ -248,6 +249,12 @@ impl PhysFrame { Ok(PhysFrame::containing_address(address)) } + /// Returns a range of pages, exclusive `end`. + #[inline] + pub const fn range(start: Self, end: Self) -> PhysFrameRange { + PhysFrameRange { start, end } + } + /// Returns the frame that contains the given physical address. #[inline] pub fn containing_address(address: PhysAddr) -> Self { @@ -289,6 +296,7 @@ impl fmt::Debug for PhysFrame { impl Add for PhysFrame { type Output = Self; + #[inline] fn add(self, rhs: u64) -> Self::Output { PhysFrame::containing_address(self.start_address() + rhs * S::SIZE) @@ -304,6 +312,7 @@ impl AddAssign for PhysFrame { impl Sub for PhysFrame { type Output = Self; + #[inline] fn sub(self, rhs: u64) -> Self::Output { PhysFrame::containing_address(self.start_address() - rhs * S::SIZE) @@ -319,6 +328,7 @@ impl SubAssign for PhysFrame { impl Sub> for PhysFrame { type Output = u64; + #[inline] fn sub(self, rhs: PhysFrame) -> Self::Output { (self.start_address - rhs.start_address) / S::SIZE diff --git a/src/aero_kernel/src/mem/paging/page_table.rs b/src/aero_kernel/src/mem/paging/page_table.rs index 1e6c149e757..bf20f8aa598 100644 --- a/src/aero_kernel/src/mem/paging/page_table.rs +++ b/src/aero_kernel/src/mem/paging/page_table.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! Abstractions for page tables and page table entries. @@ -51,7 +49,7 @@ impl PageTableEntry { // page table entry counter. const COUNTER_MASK: u64 = 0x7ff0_0000_0000_0000; const COUNTER_SHIFT: u64 = 52; - const FLAGS_MASK: u64 = 0x80000000000001ff; + const FLAGS_MASK: u64 = 0x8000_0000_0000_01ff; /// Creates an unused page table entry. pub const fn new() -> Self { @@ -59,6 +57,7 @@ impl PageTableEntry { } /// Returns whether this entry is zero. + #[inline] pub const fn is_unused(&self) -> bool { self.entry == 0 } @@ -129,7 +128,7 @@ impl PageTableEntry { /// /// - `FrameError::FrameNotPresent` if the entry doesn't have the `PRESENT` flag set. /// - `FrameError::HugeFrame` if the entry has the `HUGE_PAGE` flag set (for huge pages the - /// `addr` function must be used) + /// `addr` function must be used) pub fn frame(&self) -> Result { if !self.flags().contains(PageTableFlags::PRESENT) { Err(FrameError::FrameNotPresent) @@ -184,6 +183,7 @@ impl fmt::Debug for PageTableEntry { bitflags! { /// Possible flags for a page table entry. + #[derive(Debug, Copy, Clone)] pub struct PageTableFlags: u64 { /// Specifies whether the mapped frame or page table is loaded in memory. const PRESENT = 1; diff --git a/src/aero_kernel/src/mem/pti.rs b/src/aero_kernel/src/mem/pti.rs index 3a562800f1e..edd5b867e66 100644 --- a/src/aero_kernel/src/mem/pti.rs +++ b/src/aero_kernel/src/mem/pti.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! PTI (Page Table Isolation) is a feature that mitigates the Meltdown security //! vulnerability (affecting mainly Intel's x86 CPUs) and improves kernel hardening against diff --git a/src/aero_kernel/src/mem/slab.rs b/src/aero_kernel/src/mem/slab.rs new file mode 100644 index 00000000000..b92f46d8fdb --- /dev/null +++ b/src/aero_kernel/src/mem/slab.rs @@ -0,0 +1,158 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::ptr::NonNull; + +use intrusive_collections::UnsafeRef; + +use crate::mem::paging::*; +use crate::utils::sync::Mutex; + +#[repr(C)] +pub struct SlabHeader { + /// Reference to the slab pool. + ptr: UnsafeRef, +} + +impl SlabHeader { + /// Gets the [`SlabHeader`] from an allocated object. + pub fn from_object<'a>(ptr: *const u8) -> &'a Self { + assert!(!ptr.is_null()); + + let ptr = (ptr as usize & !(0xfff)) as *mut SlabHeader; + unsafe { &*ptr } + } + + /// Returns the slab pool to which this header belongs to. + pub fn as_slab(&self) -> &SmallSlab { + self.ptr.as_ref() + } +} + +const_assert_eq!(core::mem::size_of::(), 8); + +unsafe impl Send for SlabHeader {} +unsafe impl Sync for SlabHeader {} + +/// For small slabs, the [`BufCtl`]s are stored inline. +struct BufCtl(Option>); + +impl BufCtl { + const NULL: Self = Self(None); + + /// Constructs a [`BufCtl`] from a raw pointer. + const fn from_ptr(ptr: *mut BufCtl) -> Self { + assert!(!ptr.is_null()); + + // SAFETY: We have verified above that the pointer is non-null. + Self(Some(unsafe { NonNull::new_unchecked(ptr) })) + } +} + +const_assert_eq!(core::mem::size_of::(), 8); + +unsafe impl Send for BufCtl {} +unsafe impl Sync for BufCtl {} + +/// Used for allocations smaller than `1/8` of a page. +pub struct SmallSlab { + /// Size of the slab. + size: usize, + first_free: Mutex, +} + +impl SmallSlab { + pub const fn new(size: usize) -> Self { + assert!(size.is_power_of_two()); + + Self { + size, + first_free: Mutex::new(BufCtl::NULL), + } + } + + pub fn alloc(&self) -> *mut u8 { + let mut first_free = self.first_free.lock_irq(); + + if let Some(entry) = first_free.0 { + *first_free = BufCtl(unsafe { entry.as_ref() }.0); + entry.as_ptr().cast() + } else { + drop(first_free); + + self.expand(); + self.alloc() + } + } + + pub fn dealloc(&self, ptr: *mut u8) { + assert!(!ptr.is_null()); + + let mut first_free = self.first_free.lock_irq(); + + let mut new_head = BufCtl::from_ptr(ptr.cast()); + new_head.0 = first_free.0; + *first_free = new_head; + } + + fn expand(&self) { + let frame: PhysFrame = FRAME_ALLOCATOR.allocate_frame().expect("slab: OOM"); + + let ptr = frame.start_address().as_hhdm_virt().as_mut_ptr::(); + let header_size = + align_up(core::mem::size_of::() as u64, self.size as u64) as usize; + + let avaliable_size = Size4KiB::SIZE as usize - header_size; + let slab_ptr = unsafe { &mut *ptr.cast::() }; + + // SAFETY: We are constructing an [`UnsafeRef`] from ourselves which is a valid reference. + slab_ptr.ptr = unsafe { UnsafeRef::from_raw(self as *const _) }; + + let first_free = unsafe { ptr.add(header_size).cast() }; + *self.first_free.lock_irq() = BufCtl::from_ptr(first_free); + + // Initialize the free-list: + // + // For objects smaller than 1/8 of a page, A slab is built by allocating a 4KiB page, + // placing the slab header at the end, and dividing the rest into equal-size buffers: + // + // ------------------------------------------------------ + // | buffer | buffer | buffer | buffer | slab header + // ------------------------------------------------------ + // 4KiB + let max = (avaliable_size / self.size) - 1; + let fact = self.size / 8; + + for i in 0..max { + unsafe { + let entry = first_free.add(i * fact); + let next = first_free.add((i + 1) * fact); + + (*entry).0 = Some(NonNull::new_unchecked(next)); + } + } + + unsafe { + let entry = &mut *first_free.add(max * fact); + *entry = BufCtl::NULL; + } + } + + pub fn size(&self) -> usize { + self.size + } +} diff --git a/src/aero_kernel/src/mem/vmalloc.rs b/src/aero_kernel/src/mem/vmalloc.rs index e10f4306458..656b7a9bdd7 100644 --- a/src/aero_kernel/src/mem/vmalloc.rs +++ b/src/aero_kernel/src/mem/vmalloc.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! Due to internal-fragmentation in the buddy frame allocator, we cannot allocate large //! amount of contiguous physical memory. We instead use [`vmalloc`] to allocate virtually @@ -109,10 +107,10 @@ impl Vmalloc { .find(|(_, area)| area.protected.lock().size >= size_bytes)?; let mut area_p = area.protected.lock(); - let address = area_p.addr.clone(); + let address = area_p.addr; if area_p.size > size_bytes { - area_p.addr = area_p.addr + size_bytes; + area_p.addr += size_bytes; area_p.size -= size_bytes; } else { // NOTE: the area is has exactly the requested size, so we can remove it @@ -205,5 +203,8 @@ pub fn init() { /// ## Panics /// * If the `vmalloc` allocator is not initialized. pub(super) fn get_vmalloc() -> MutexGuard<'static, Vmalloc> { - VMALLOC.get().expect("get_vmalloc: not initialized").lock() + VMALLOC + .get() + .expect("get_vmalloc: not initialized") + .lock_irq() } diff --git a/src/aero_kernel/src/modules.rs b/src/aero_kernel/src/modules.rs index c38e6376311..133a8cc13ba 100644 --- a/src/aero_kernel/src/modules.rs +++ b/src/aero_kernel/src/modules.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! A kernel module is an object file that contains code that can extend //! the kernel functionality at runtime. When a kernel module is no longer needed, @@ -31,30 +29,41 @@ //! aero_kernel::module_exit!(hello_exit); //! ``` -use crate::utils::linker::LinkerSymbol; +use core::mem::size_of; -/// Inner helper function to make sure the function provided to the [module_init] macro +use crate::{drivers, extern_sym, fs}; + +/// Inner helper function to make sure the function provided to the [`module_init`] macro /// has a valid function signature. This function returns the passed module init function as /// a const void pointer. -#[inline] -pub const fn make_module_init(init_function: fn() -> ()) -> ModuleInit { - ModuleInit(init_function as *const ()) + +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] +#[repr(C)] +pub enum ModuleType { + Block = 0, + Other = 1, } -/// Inner helper structure holding the module init function as a void pointer. This struct -/// is required as we cannot directly store a pointer in the static as it needs to implement -/// [Sync]. -pub struct ModuleInit(*const ()); +#[derive(Debug, Clone)] +#[repr(C)] +pub struct Module { + pub init: *const (), + pub ty: ModuleType, +} -unsafe impl Sync for ModuleInit {} +unsafe impl Sync for Module {} #[macro_export] macro_rules! module_init { - ($init_function:expr) => { + ($init_function:expr, $ty:path) => { + use $crate::modules::ModuleType; + #[used] #[link_section = ".kernel_modules.init"] - static __MODULE_INIT: $crate::modules::ModuleInit = - $crate::modules::make_module_init($init_function); + static __MODULE_INIT: $crate::modules::Module = $crate::modules::Module { + init: $init_function as *const (), + ty: $ty, + }; }; } @@ -62,18 +71,36 @@ macro_rules! module_init { /// we cannot read the ext2 root filesystem, we link all of the kernel modules into the kernel /// itself (this is temporary and modules will be loaded from the filesystem in the future). pub(crate) fn init() { - extern "C" { - static __kernel_modules_start: LinkerSymbol; - static __kernel_modules_end: LinkerSymbol; - } + let modules_start = extern_sym!(__kernel_modules_start).cast::(); + let modules_end = extern_sym!(__kernel_modules_end).cast::(); + + let size = (modules_end.addr() - modules_start.addr()) / size_of::(); + let modules = unsafe { core::slice::from_raw_parts(modules_start, size) }; - /* - * Iterate over the `kernel_modules` linker section containing pointers to module - * initialization functions. - */ unsafe { - (__kernel_modules_start.as_usize()..__kernel_modules_end.as_usize()) - .step_by(0x08) - .for_each(|module| (*(module as *mut fn() -> ()))()); + // TODO: refactor this out + let mut modules = modules.to_vec(); + modules.sort_by(|e, a| e.ty.cmp(&a.ty)); + + let mut launched_fs = false; + + for module in modules { + log::debug!("{module:?} {launched_fs}"); + + if module.ty != ModuleType::Block && !launched_fs { + let mut address_space = crate::mem::AddressSpace::this(); + let mut offset_table = address_space.offset_page_table(); + + #[cfg(target_arch = "x86_64")] + drivers::pci::init(&mut offset_table); + log::info!("loaded PCI driver"); + + fs::block::launch().unwrap(); + launched_fs = true; + } + + let init = core::mem::transmute::<*const (), fn() -> ()>(module.init); + init(); + } } } diff --git a/src/aero_kernel/src/net/arp.rs b/src/aero_kernel/src/net/arp.rs new file mode 100644 index 00000000000..bed1a21598c --- /dev/null +++ b/src/aero_kernel/src/net/arp.rs @@ -0,0 +1,219 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +//! Address Resolution Protocol + +use alloc::collections::BTreeMap; +use alloc::vec::Vec; +use spin::{Once, RwLock}; + +use crate::net::default_device; +use crate::net::shim::PacketSend; + +use crabnet::data_link::{Arp, ArpAddress, ArpHardwareType, ArpOpcode, Eth, EthType, MacAddr}; +use crabnet::network::Ipv4Addr; + +use super::RawPacket; + +enum Status { + Resolved, + Pending(Vec), +} + +struct Entry { + mac: MacAddr, + status: Status, +} + +impl Entry { + fn new(mac: MacAddr, status: Status) -> Self { + Self { mac, status } + } +} + +struct Cache(BTreeMap); + +impl Cache { + fn new() -> Self { + Self(BTreeMap::new()) + } + + fn insert(&mut self, ip: Ipv4Addr, mac: MacAddr) { + if let Some(entry) = self.0.get_mut(&ip) { + let status = core::mem::replace(&mut entry.status, Status::Resolved); + + if let Status::Pending(queue) = status { + entry.mac = mac; + entry.status = Status::Resolved; + + for mut packet in queue { + log::trace!("[ ARP ] (!!) Sending queued packed to {ip:?} {mac:?}"); + + // FIXME: make this cleaner + let eth = unsafe { &mut *packet.as_mut_ptr().cast::() }; + eth.dest_mac = mac; + + super::default_device().send(packet); + } + } + } else { + self.0.insert(ip, Entry::new(mac, Status::Resolved)); + } + } + + fn request(&mut self, ip: Ipv4Addr, packet: RawPacket) { + assert!(ip != Ipv4Addr::LOOPBACK); + + if self.0.get_mut(&ip).is_some() { + todo!() + } else { + let queue = alloc::vec![packet]; + let entry = Entry::new(MacAddr::NULL, Status::Pending(queue)); + + self.0.insert(ip, entry); + } + } + + fn get(&self, ip: Ipv4Addr) -> Option { + if let Some(entry) = self.0.get(&ip) { + return Some(entry.mac); + } + + None + } +} + +static CACHE: Once> = Once::new(); + +pub fn get(ip: Ipv4Addr) -> Option { + CACHE + .get() + .as_ref() + .expect("arp: cache not initialized") + .read() + .get(ip) +} + +pub fn init() { + CACHE.call_once(|| { + let mut cache = Cache::new(); + cache.insert(Ipv4Addr::BROADCAST, MacAddr::BROADCAST); + + RwLock::new(cache) + }); +} + +// #[derive(Debug, Copy, Clone)] +// pub struct Arp {} + +// impl Packet { +// pub fn create() -> Packet { +// let device = default_device(); + +// let mut packet: Packet = +// Packet::::create(ethernet::Type::Arp, +// core::mem::size_of::()).upgrade(); + +// let header = packet.header_mut(); +// header.htype = HType::Ethernet; +// header.ptype = PType::Ipv4; +// header.hlen = BigEndian::from(MacAddr::ADDR_SIZE as u8); +// header.plen = BigEndian::from(Ipv4Addr::ADDR_SIZE as u8); + +// header.src_ip = device.ip(); +// header.src_mac = device.mac(); + +// packet +// } +// } + +// impl ConstPacketKind for Arp { +// const HSIZE: usize = core::mem::size_of::(); +// } + +// impl PacketUpHierarchy for Packet {} +// impl PacketHeader for Packet { +// fn recv(&self) { +// let header = self.header(); + +// CACHE +// .get() +// .as_ref() +// .expect("arp: cache not initialized") +// .write() +// .insert(header.src_ip, header.src_mac); + +// let device = default_device(); + +// if header.opcode() == Opcode::Request && header.dest_ip == device.ip() { +// let mut packet = Packet::::create(); +// let reply_header = packet.header_mut(); + +// reply_header.opcode = Opcode::Reply; +// reply_header.dest_ip = header.src_ip; +// reply_header.dest_mac = header.src_mac; + +// packet.send(); +// } +// } +// } + +pub fn do_recv(arp: &Arp) { + CACHE + .get() + .as_ref() + .expect("arp: cache not initialized") + .write() + .insert(arp.src_ip(), arp.src_mac()); + + let device = default_device(); + + if arp.opcode() == ArpOpcode::Request && arp.dest_ip() == device.ip() { + let addr = ArpAddress::new(arp.src_mac(), arp.src_ip()); + let reply_arp = make_arp(ArpOpcode::Reply, addr); + + reply_arp.send(); + } +} + +pub fn request_ip(target: Ipv4Addr, to: RawPacket) { + let arp = make_arp(ArpOpcode::Request, ArpAddress::new(MacAddr::NULL, target)); + + log::debug!("[ ARP ] (!!) Sending request for {target:?}"); + + CACHE + .get() + .as_ref() + .expect("arp: cache not initialized") + .write() + .request(target, to); + + arp.send(); +} + +fn make_arp(opcode: ArpOpcode, dest_addr: ArpAddress) -> Arp { + let device = default_device(); + let src_addr = ArpAddress::new(device.mac(), device.ip()); + + Arp::new( + ArpHardwareType::Ethernet, + EthType::Ip, + src_addr, + dest_addr, + opcode, + ) +} diff --git a/src/aero_kernel/src/net/loopback.rs b/src/aero_kernel/src/net/loopback.rs new file mode 100644 index 00000000000..ff0aebc684e --- /dev/null +++ b/src/aero_kernel/src/net/loopback.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +//! Loopback device. + +use alloc::boxed::Box; +use alloc::sync::Arc; +use crabnet::data_link::MacAddr; +use crabnet::network::Ipv4Addr; + +use crate::utils::dma::DmaAllocator; + +use super::{NetworkDevice, NetworkDriver, RecvPacket}; + +pub struct Loopback; + +impl NetworkDriver for Loopback { + fn send(&self, _packet: Box<[u8], DmaAllocator>) { + todo!() + } + + fn recv(&self) -> RecvPacket { + todo!() + } + + fn recv_end(&self, _packet_id: usize) { + todo!() + } + + #[inline] + fn mac(&self) -> MacAddr { + // TODO: What should this really be? + MacAddr::NULL + } +} + +lazy_static::lazy_static! { + pub static ref LOOPBACK: Arc = { + let device = Arc::new(NetworkDevice::new(Arc::new(Loopback))); + + device.set_ip(Ipv4Addr::LOOPBACK); + device.set_subnet_mask(Ipv4Addr::new(255, 0, 0, 0)); + + device + }; +} diff --git a/src/aero_kernel/src/net/mod.rs b/src/aero_kernel/src/net/mod.rs new file mode 100644 index 00000000000..756b7fc9c85 --- /dev/null +++ b/src/aero_kernel/src/net/mod.rs @@ -0,0 +1,313 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec::Vec; +use crabnet::transport::TcpOptions; +use spin::RwLock; + +pub mod arp; +pub mod loopback; +pub mod tcp; +pub mod udp; + +use crate::userland::scheduler; +use crate::userland::task::Task; +use crate::utils::dma::DmaAllocator; + +use crabnet::data_link::MacAddr; +use crabnet::network::Ipv4Addr; + +#[downcastable] +pub trait NetworkDriver: Send + Sync { + fn send(&self, packet: Box<[u8], DmaAllocator>); + fn recv(&self) -> RecvPacket; + fn recv_end(&self, packet_id: usize); + fn mac(&self) -> MacAddr; +} + +#[derive(Default)] +struct Metadata { + ip: Ipv4Addr, + #[allow(dead_code)] + subnet_mask: Ipv4Addr, + default_gateway: Ipv4Addr, +} + +// FIXME(andypython): This is very inefficient. We store the driver as an Arc and +// the device with metadata as an Arc. Two heap allocations for nothing, bruh +// moments. +pub struct NetworkDevice { + driver: Arc, + metadata: RwLock, +} + +impl NetworkDevice { + pub fn new(driver: Arc) -> Self { + // FIXME(andy): DHCPD should handle static IP assignment. + // + // https://wiki.qemu.org/Documentation/Networking + let metadata = Metadata { + ip: Ipv4Addr::new(192, 168, 100, 0), + // What should the default be? Also this should really be handled inside dhcpd. + default_gateway: Ipv4Addr::new(10, 0, 2, 2), + subnet_mask: Ipv4Addr::new(255, 255, 255, 0), + }; + + Self { + driver, + metadata: RwLock::new(metadata), + } + } + + pub fn set_ip(&self, ip: Ipv4Addr) { + self.metadata.write().ip = ip; + } + + pub fn set_subnet_mask(&self, mask: Ipv4Addr) { + self.metadata.write().ip = mask; + } + + pub fn ip(&self) -> Ipv4Addr { + self.metadata.read().ip + } + + pub fn subnet_mask(&self) -> Ipv4Addr { + self.metadata.read().subnet_mask + } + + #[inline] + pub fn default_gateway(&self) -> Ipv4Addr { + self.metadata.read().default_gateway + } +} + +impl core::ops::Deref for NetworkDevice { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.driver + } +} + +#[derive(Debug)] +pub struct RecvPacket<'a> { + pub packet: &'a [u8], + pub id: usize, +} + +impl<'a> Drop for RecvPacket<'a> { + fn drop(&mut self) { + default_device().recv_end(self.id) + } +} + +static DEVICES: RwLock>> = RwLock::new(Vec::new()); +static DEFAULT_DEVICE: RwLock>> = RwLock::new(None); + +fn packet_processor_thread() { + use crabnet::data_link::{Arp, Eth, EthType}; + use crabnet::network::{Ipv4, Ipv4Type}; + use crabnet::transport::{Tcp, Udp}; + use crabnet::PacketParser; + + let device = default_device(); + + loop { + let packet = device.recv(); + + let mut parser = PacketParser::new(packet.packet); + let eth = parser.next::(); + + match eth.typ() { + EthType::Ip => { + let ip = parser.next::(); + + match ip.protocol() { + Ipv4Type::Udp => { + let udp = parser.next::(); + let size = ip.payload_len() as usize - core::mem::size_of::(); + + let payload = &parser.payload()[..size]; + udp::on_packet(udp, payload); + } + + Ipv4Type::Tcp => { + let tcp = parser.next::(); + let size = ip.payload_len() as usize - tcp.header_size() as usize; + let options = parser.next::(); + let payload = &parser.payload()[..size]; + + tcp::on_packet(tcp, &options, payload) + } + } + } + + EthType::Arp => { + arp::do_recv(parser.next::()); + } + } + } +} + +pub fn add_device(device: NetworkDevice) { + let device = Arc::new(device); + DEVICES.write().push(device.clone()); + + let mut default_device = DEFAULT_DEVICE.write(); + if default_device.is_none() { + *default_device = Some(device); + } + + scheduler::get_scheduler().register_task(Task::new_kernel(packet_processor_thread, true)); +} + +pub fn has_default_device() -> bool { + DEFAULT_DEVICE.read().as_ref().is_some() +} + +pub fn default_device() -> Arc { + DEFAULT_DEVICE + .read() + .as_ref() + .expect("net: no devices found") + .clone() +} + +// Initialize the networking stack. +pub fn init() { + if !has_default_device() { + // No network devices are avaliable. + return; + } + + DEVICES.write().push(loopback::LOOPBACK.clone()); + arp::init(); + log::info!("net::arp: initialized cache"); +} + +pub type RawPacket = Box<[u8], DmaAllocator>; + +pub mod shim { + use crate::net::{self, arp}; + use crate::utils::dma::DmaAllocator; + + use crabnet::data_link::{Arp, Eth, EthType, MacAddr}; + use crabnet::network::Ipv4; + use crabnet::{IntoBoxedBytes, Protocol, Stacked}; + + pub trait PacketSend { + fn send(self); + } + + // Deref for Stacked where T: Stacked? + // + // TODO(andypython): Can all of the packet send impls be refactored? + impl PacketSend for Stacked, T>, U> { + fn send(mut self) { + let device = net::default_device(); + + let eth = &mut self.upper.upper.upper; + let ip = &self.upper.upper.lower; + + let mut dest_ip = ip.dest_ip(); + + if !dest_ip.is_broadcast() && !dest_ip.is_same_subnet(device.ip(), device.subnet_mask()) + { + dest_ip = device.default_gateway(); + } + + eth.src_mac = device.mac(); + + if let Some(addr) = arp::get(dest_ip) { + eth.dest_mac = addr; + device.send(self.into_boxed_bytes_in(DmaAllocator)); + } else { + arp::request_ip(dest_ip, self.into_boxed_bytes_in(DmaAllocator)); + } + } + } + + impl PacketSend + for Stacked, T>, U>, S> + { + fn send(mut self) { + let device = net::default_device(); + + let eth = &mut self.upper.upper.upper.upper; + let ip = &self.upper.upper.upper.lower; + + let mut dest_ip = ip.dest_ip(); + + if !dest_ip.is_broadcast() && !dest_ip.is_same_subnet(device.ip(), device.subnet_mask()) + { + dest_ip = device.default_gateway(); + } + + eth.src_mac = device.mac(); + + if let Some(addr) = arp::get(dest_ip) { + eth.dest_mac = addr; + device.send(self.into_boxed_bytes_in(DmaAllocator)); + } else { + arp::request_ip(dest_ip, self.into_boxed_bytes_in(DmaAllocator)); + } + } + } + + impl PacketSend for Arp { + fn send(self) { + let device = net::default_device(); + + let eth = Eth::new(MacAddr::NULL, MacAddr::BROADCAST, EthType::Arp) + .set_dest_mac(self.dest_mac()) + .set_src_mac(device.mac()); + + device.send((eth / self).into_boxed_bytes_in(DmaAllocator)); + } + } + + // struct DefaultDevice; + + // impl NetworkDevice for DefaultDevice { + // fn send_bytes(&self, bytes: Box<[u8], A>) { + // panic!("Sending {} bytes", bytes.len()); + // } + // } + + // pub trait NetworkDevice { + // fn send_bytes(&self, bytes: Box<[u8], A>); + // } + + // pub trait SendablePacket + // where + // Self: Sized + IntoBoxedBytes, + // { + // #[inline] + // fn send(self) { + // DefaultDevice.send_bytes(self.into_boxed_bytes()) + // } + + // #[inline] + // fn send_in>(self, device: &T) { + // device.send_bytes(self.into_boxed_bytes()) + // } + // } + + // impl SendablePacket for T {} +} diff --git a/src/aero_kernel/src/net/tcp.rs b/src/aero_kernel/src/net/tcp.rs new file mode 100644 index 00000000000..2889545cf1a --- /dev/null +++ b/src/aero_kernel/src/net/tcp.rs @@ -0,0 +1,63 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use alloc::collections::BTreeMap; +use alloc::sync::Arc; + +use crabnet::transport::{Tcp, TcpOptions}; +use spin::RwLock; + +use crate::socket::tcp::TcpSocket; + +static HANDLERS: RwLock>> = RwLock::new(BTreeMap::new()); + +pub fn on_packet(tcp: &Tcp, options: &TcpOptions, payload: &[u8]) { + let handlers = HANDLERS.read(); + + if let Some(handler) = handlers.get(&tcp.dest_port()) { + handler.on_packet(tcp, options, payload); + } else { + log::warn!("tcp: no handler registered for port {}", tcp.dest_port()); + } +} + +pub trait TcpHandler: Send + Sync { + fn recv(&self, packet: &Tcp, payload: &[u8]); +} + +pub fn alloc_ephemeral_port(socket: Arc) -> Option { + const EPHEMERAL_START: u16 = 49152; + const EPHEMERAL_END: u16 = u16::MAX; + + let mut handlers = HANDLERS.write(); + + // Ephemeral ports in the range 49152..65535 are not + // assigned, controlled, or registered and are used + // for temporary or private ports. + for port in EPHEMERAL_START..=EPHEMERAL_END { + if handlers.contains_key(&port) { + continue; + } + + log::warn!("[ TCP ] Listening on port {port}"); + + handlers.insert(port, socket); + return Some(port); + } + + None +} diff --git a/src/aero_kernel/src/net/udp.rs b/src/aero_kernel/src/net/udp.rs new file mode 100644 index 00000000000..1d4599df7d9 --- /dev/null +++ b/src/aero_kernel/src/net/udp.rs @@ -0,0 +1,77 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use spin::RwLock; + +use crabnet::network::Ipv4Addr; +use crabnet::transport::Udp; + +pub fn on_packet(udp: &Udp, payload: &[u8]) { + let dest_port = udp.dst_port(); + + let handlers = HANDLERS.read(); + + if let Some(handler) = handlers.get(&dest_port) { + handler.recv(udp, payload); + } else { + log::warn!("udp: no handler registered for port {}", dest_port); + } +} + +static HANDLERS: RwLock>> = RwLock::new(BTreeMap::new()); + +pub trait UdpHandler: Send + Sync { + fn recv(&self, udp: &Udp, payload: &[u8]); +} + +pub fn alloc_ephemeral_port(socket: Arc) -> Option { + const EPHEMERAL_START: u16 = 49152; + const EPHEMERAL_END: u16 = u16::MAX; + + let mut handlers = HANDLERS.write(); + + // Ephemeral ports in the range 49152..65535 are not + // assigned, controlled, or registered and are used + // for temporary or private ports. + for port in EPHEMERAL_START..=EPHEMERAL_END { + if handlers.contains_key(&port) { + continue; + } + + log::warn!("[ UDP ] Listening on port {port}"); + handlers.insert(port, socket); + return Some(port); + } + + None +} + +pub fn bind(port: u16, socket: Arc) { + log::trace!("udp: bind(port={port})"); + + let mut handlers = HANDLERS.write(); + // check if the port is already in use + assert!(!handlers.contains_key(&port)); + + handlers.insert(port, socket); +} + +pub fn connect(host: Ipv4Addr, port: u16) { + log::trace!("udp: connect(host={host:?}, port={port})"); +} diff --git a/src/aero_kernel/src/rendy.rs b/src/aero_kernel/src/rendy.rs index 7952abbd4d6..29e3a8513e2 100644 --- a/src/aero_kernel/src/rendy.rs +++ b/src/aero_kernel/src/rendy.rs @@ -1,31 +1,32 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::fmt::Write; use core::fmt; -use core::u8; +use core::ops::{Index, IndexMut}; +use core::ptr::NonNull; +use core::time::Duration; use alloc::boxed::Box; -use limine::LimineFramebuffer; +use limine::framebuffer::Framebuffer; use spin::Once; +use vte::ansi::{Handler, NamedColor, Timeout}; use crate::cmdline::CommandLine; use crate::mem; @@ -33,6 +34,8 @@ use crate::mem::paging::align_up; use crate::utils::sync::Mutex; +use vte::ansi::{Attr, Processor}; + static FONT: &[[u8; FONT_HEIGHT]; FONT_GLYPHS] = unsafe { &core::mem::transmute(*include_bytes!("../../font.bin")) }; @@ -175,8 +178,7 @@ struct Image { } fn parse_bmp_image(data: &[u8]) -> Image { - let header: &BmpHeader = - unsafe { core::mem::transmute(data as *const [u8] as *const u8 as *const BmpHeader) }; + let header: &BmpHeader = unsafe { &*(data.as_ptr().cast::()) }; // Check if the BMP image has the correct signature (ie. "BM"). assert!(&header.bf_signature == b"BM"); @@ -187,7 +189,7 @@ fn parse_bmp_image(data: &[u8]) -> Image { let mut image = mem::alloc_boxed_buffer::(header.bf_size as usize); let bytes = image.len(); - (&mut image[..bytes - header.bf_offset as usize]) + image[..bytes - header.bf_offset as usize] .copy_from_slice(&data[header.bf_offset as usize..header.bf_size as usize]); Image { @@ -200,9 +202,82 @@ fn parse_bmp_image(data: &[u8]) -> Image { } } -pub struct DebugRendy<'this> { - /// The raw framebuffer pointer queried from the BIOS or UEFI firmware represented - /// as a [u8] slice. +#[derive(Default)] +struct RendySync; + +impl Timeout for RendySync { + fn set_timeout(&mut self, _duration: Duration) { + unimplemented!() + } + + fn clear_timeout(&mut self) { + unimplemented!() + } + + fn pending_timeout(&self) -> bool { + false + } +} + +const COLOR_COUNT: usize = 269; + +struct ColorList([u32; COLOR_COUNT]); + +impl ColorList { + fn new() -> Self { + let mut list = Self([0; COLOR_COUNT]); + + // The color values are based from the default alacritty colors. + // + // Normal colors: + list[NamedColor::Black] = 0x1d1f21; + list[NamedColor::Red] = 0xcc6666; + list[NamedColor::Green] = 0xb5bd68; + list[NamedColor::Yellow] = 0xf0c674; + list[NamedColor::Blue] = 0x81a2be; + list[NamedColor::Magenta] = 0xb294bb; + list[NamedColor::Cyan] = 0x8abeb7; + list[NamedColor::White] = 0xc5c8c6; + // Bright colors: + list[NamedColor::BrightBlack] = 0x666666; + list[NamedColor::BrightRed] = 0xd54e53; + list[NamedColor::BrightGreen] = 0xb9ca4a; + list[NamedColor::BrightYellow] = 0xe7c547; + list[NamedColor::BrightBlue] = 0x7aa6da; + list[NamedColor::BrightMagenta] = 0xc397d8; + list[NamedColor::BrightCyan] = 0x70c0b1; + list[NamedColor::BrightWhite] = 0xeaeaea; + + list + } +} + +impl Index for ColorList { + type Output = u32; + + #[inline] + fn index(&self, idx: NamedColor) -> &Self::Output { + &self.0[idx as usize] + } +} + +impl IndexMut for ColorList { + #[inline] + fn index_mut(&mut self, idx: NamedColor) -> &mut Self::Output { + &mut self.0[idx as usize] + } +} + +impl Index for ColorList { + type Output = u32; + + #[inline] + fn index(&self, idx: usize) -> &Self::Output { + &self.0[idx] + } +} + +pub struct Inner<'this> { buffer: &'this mut [u32], info: RendyInfo, @@ -220,7 +295,7 @@ pub struct DebugRendy<'this> { queue: Box<[QueueCharacter]>, grid: Box<[Character]>, - map: Box<[Option<*mut QueueCharacter>]>, + map: Box<[Option>]>, bg_canvas: Box<[u32]>, queue_cursor: usize, @@ -230,72 +305,11 @@ pub struct DebugRendy<'this> { cursor_visibility: bool, auto_flush: bool, -} - -impl<'this> DebugRendy<'this> { - /// Create a new debug renderer with the default foreground color set to white and - /// background color set to black. - pub fn new(buffer: &'this mut [u32], info: RendyInfo, cmdline: &CommandLine) -> Self { - let width = info.horizontal_resolution; - let height = info.vertical_resolution; - - let offset_x = DEFAULT_MARGIN + ((width - DEFAULT_MARGIN * 2) % FONT_WIDTH) / 2; - let offset_y = DEFAULT_MARGIN + ((height - DEFAULT_MARGIN * 2) % FONT_HEIGHT) / 2; - - let cols = (width - DEFAULT_MARGIN * 2) / FONT_WIDTH; - let rows = (height - DEFAULT_MARGIN * 2) / FONT_HEIGHT; - - let grid_size = rows * cols * core::mem::size_of::(); - let grid = mem::alloc_boxed_buffer::(grid_size); - - let queue_size = rows * cols * core::mem::size_of::(); - let queue = mem::alloc_boxed_buffer::(queue_size); - - let map_size = rows * cols * core::mem::size_of::>(); - let map = mem::alloc_boxed_buffer::>(map_size); - - let bg_canvas_size = width * height * core::mem::size_of::(); - let bg_canvas = mem::alloc_boxed_buffer::(bg_canvas_size); - - let mut this = Self { - buffer, - info, - x_pos: 0, - y_pos: 0, - - old_x_pos: 0, - old_y_pos: 0, - - rows, - cols, - - theme_background: cmdline.theme_background, - color: ColorCode::new(DEFAULT_TEXT_FOREGROUND, DEFAULT_TEXT_BACKGROUND), - - queue, - grid, - map, - bg_canvas, - - queue_cursor: 0, - - offset_x, - offset_y, - - cursor_visibility: true, - auto_flush: true, - }; - - let image = cmdline.term_background.map(|a| parse_bmp_image(a)); - - this.generate_canvas(image); - this.clear(true); - this.double_buffer_flush(); - - this - } + color_list: ColorList, +} +impl Inner<'_> { fn genloop( &mut self, image: &Image, @@ -357,11 +371,9 @@ impl<'this> DebugRendy<'this> { let mut img_x = ratio * xstart; for x in xstart..xend { - let img_pixel = unsafe { - (image.image.as_ptr()).add(fixedp6_to_int(img_x) * col_size + off) as *const u32 - }; - - let i = blender(x, y, unsafe { *img_pixel }); + let offset = fixedp6_to_int(img_x) * col_size + off; + let img_pixel: [u8; 4] = unsafe { *image.image.as_ptr().add(offset).cast() }; + let i = blender(x, y, u32::from_le_bytes(img_pixel)); unsafe { *self.buffer.as_mut_ptr().add(fb_off + x) = i as u32; @@ -373,7 +385,7 @@ impl<'this> DebugRendy<'this> { } } - pub fn get_framebuffer<'a>(&'a mut self) -> &'a mut [u32] { + pub fn get_framebuffer(&mut self) -> &mut [u32] { self.buffer } @@ -404,15 +416,14 @@ impl<'this> DebugRendy<'this> { let g = (alpha * (fg >> 8) as u8 as u32 + inv_alpha * (bg >> 8) as u8 as u32) / 256; let b = (alpha * fg as u8 as u32 + inv_alpha * bg as u8 as u32) / 256; - (0 << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) + ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) }; let theme_background = self.theme_background; - self.genloop(image, xstart, xend, ystart, yend, |_, __, c| { - let blend = color_blend(theme_background, c) as usize; - blend - }) + self.genloop(image, xstart, xend, ystart, yend, |_, __, color| { + color_blend(theme_background, color) as usize + }); } fn generate_canvas(&mut self, image: Option) { @@ -482,13 +493,13 @@ impl<'this> DebugRendy<'this> { queue.x = x; queue.y = y; - self.map[i] = Some(queue as *mut _); + self.map[i] = Some(NonNull::from(queue)); } let item = self.map[i]; unsafe { - (&mut *item.unwrap()).char = *char; + item.unwrap().as_mut().char = *char; } } @@ -509,41 +520,25 @@ impl<'this> DebugRendy<'this> { } } - fn set_auto_flush(&mut self, yes: bool) { - self.auto_flush = yes; - } - - fn write_string(&mut self, string: &str) { - for char in string.chars() { - self.write_character(char) - } - - if self.auto_flush { - self.double_buffer_flush(); - } - } - fn draw_cursor(&mut self) { let i = self.x_pos + self.y_pos * self.cols; let mut char; if self.map[i].is_some() { unsafe { - char = (&mut *self.map[i].unwrap()).char; + char = self.map[i].unwrap().as_ref().char; } } else { char = self.grid[i]; } - let temp = char.fg; - char.fg = char.bg; - char.bg = temp; + core::mem::swap(&mut char.fg, &mut char.bg); self.plot_char(self.x_pos, self.y_pos, char); if self.map[i].is_some() { unsafe { - self.grid[i] = (&mut *self.map[i].unwrap()).char; + self.grid[i] = self.map[i].unwrap().as_ref().char; } self.map[i] = None; @@ -553,7 +548,7 @@ impl<'this> DebugRendy<'this> { fn plot_char(&mut self, x: usize, y: usize, char: Character) { let ch = match char.char { ch if ch.is_ascii() => ch, - _ => '?' as char, + _ => '?', }; if x >= self.cols || y >= self.rows { @@ -565,7 +560,7 @@ impl<'this> DebugRendy<'this> { let glyph = &FONT[ch as usize]; // naming: fx, fy for font coordinates and gx, gy for glyph coordinates - for gy in 0..FONT_HEIGHT { + for (gy, glyph) in glyph.iter().enumerate().take(FONT_HEIGHT) { let fb_line = unsafe { self.buffer .as_mut_ptr() @@ -579,7 +574,7 @@ impl<'this> DebugRendy<'this> { }; for gx in 0..FONT_WIDTH { - let draw = glyph[gy] & (1 << (FONT_WIDTH - gx - 1)) != 0; + let draw = *glyph & (1 << (FONT_WIDTH - gx - 1)) != 0; let color = if draw { char.fg } else if char.bg == u32::MAX { @@ -688,7 +683,7 @@ impl<'this> DebugRendy<'this> { if let Some(char) = queue { unsafe { - res = (*char).char; + res = char.as_ref().char; } } else { res = self.grid[i]; @@ -713,6 +708,118 @@ impl<'this> DebugRendy<'this> { } } + fn set_cursor_position(&mut self, x: usize, y: usize) { + assert!(x <= self.cols && y <= self.rows); + + self.x_pos = x; + self.y_pos = y; + self.double_buffer_flush(); + } +} + +pub struct DebugRendy<'a> { + inner: Inner<'a>, + performer: Processor, +} + +impl<'this> DebugRendy<'this> { + /// Create a new debug renderer with the default foreground color set to white and + /// background color set to black. + pub fn new(buffer: &'this mut [u32], info: RendyInfo, cmdline: &CommandLine) -> Self { + let width = info.horizontal_resolution; + let height = info.vertical_resolution; + + let offset_x = DEFAULT_MARGIN + ((width - DEFAULT_MARGIN * 2) % FONT_WIDTH) / 2; + let offset_y = DEFAULT_MARGIN + ((height - DEFAULT_MARGIN * 2) % FONT_HEIGHT) / 2; + + let cols = (width - DEFAULT_MARGIN * 2) / FONT_WIDTH; + let rows = (height - DEFAULT_MARGIN * 2) / FONT_HEIGHT; + + let grid = mem::alloc_boxed_buffer::(rows * cols); + let queue = mem::alloc_boxed_buffer::(rows * cols); + let map = mem::alloc_boxed_buffer::>>(rows * cols); + let bg_canvas = mem::alloc_boxed_buffer::(width * height); + + let mut this = Self { + inner: Inner { + buffer, + info, + + x_pos: 0, + y_pos: 0, + + old_x_pos: 0, + old_y_pos: 0, + + rows, + cols, + + theme_background: cmdline.theme_background, + color: ColorCode::new(DEFAULT_TEXT_FOREGROUND, DEFAULT_TEXT_BACKGROUND), + + queue, + grid, + map, + bg_canvas, + + queue_cursor: 0, + + offset_x, + offset_y, + + cursor_visibility: true, + auto_flush: true, + + color_list: ColorList::new(), + }, + performer: Processor::new(), + }; + + let image = cmdline.term_background.map(parse_bmp_image); + + this.generate_canvas(image); + this.clear(true); + this.double_buffer_flush(); + + this + } +} + +impl<'a> core::ops::Deref for DebugRendy<'a> { + type Target = Inner<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl core::ops::DerefMut for DebugRendy<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl fmt::Write for DebugRendy<'_> { + fn write_str(&mut self, string: &str) -> fmt::Result { + self.performer.advance(&mut self.inner, string.as_bytes()); + Ok(()) + } +} + +impl vte::ansi::Handler for Inner<'_> { + fn input(&mut self, c: char) { + self.write_character(c); + + if self.auto_flush { + self.double_buffer_flush(); + } + } + + #[inline] + fn linefeed(&mut self) { + self.input('\n'); + } + fn backspace(&mut self) { let empty = Character { char: ' ', @@ -731,25 +838,51 @@ impl<'this> DebugRendy<'this> { self.double_buffer_flush(); } - fn set_cursor_position(&mut self, x: usize, y: usize) { - assert!(x <= self.cols && y <= self.rows); - - self.x_pos = x; - self.y_pos = y; - self.double_buffer_flush(); - } -} + fn terminal_attribute(&mut self, attr: Attr) { + match attr { + Attr::Reset => { + self.color = ColorCode::new(DEFAULT_TEXT_FOREGROUND, DEFAULT_TEXT_BACKGROUND) + } -impl<'this> fmt::Write for DebugRendy<'this> { - fn write_str(&mut self, string: &str) -> fmt::Result { - self.write_string(string); + // Attr::Bold => todo!(), + // Attr::Dim => todo!(), + // Attr::Italic => todo!(), + // Attr::Underline => todo!(), + // Attr::DoubleUnderline => todo!(), + // Attr::Undercurl => todo!(), + // Attr::DottedUnderline => todo!(), + // Attr::DashedUnderline => todo!(), + // Attr::BlinkSlow => todo!(), + // Attr::BlinkFast => todo!(), + // Attr::Reverse => todo!(), + // Attr::Hidden => todo!(), + // Attr::Strike => todo!(), + // Attr::CancelBold => todo!(), + // Attr::CancelBoldDim => todo!(), + // Attr::CancelItalic => todo!(), + // Attr::CancelUnderline => todo!(), + // Attr::CancelBlink => todo!(), + // Attr::CancelReverse => todo!(), + // Attr::CancelHidden => todo!(), + // Attr::CancelStrike => todo!(), + Attr::Foreground(color) => { + let code = match color { + vte::ansi::Color::Named(c) => self.color_list[c], + vte::ansi::Color::Indexed(c) => self.color_list[c as usize], + _ => unimplemented!(), + }; - Ok(()) + self.color.0 = code; + } + // Attr::Background(_) => todo!(), + // Attr::UnderlineColor(_) => todo!(), + _ => {} + } } } -unsafe impl<'this> Send for DebugRendy<'this> {} -unsafe impl<'this> Sync for DebugRendy<'this> {} +unsafe impl Send for DebugRendy<'_> {} +unsafe impl Sync for DebugRendy<'_> {} pub static DEBUG_RENDY: Once> = Once::new(); @@ -764,7 +897,7 @@ pub macro println { pub macro dbg { () => { - $crate::rendy::println!("[{}:{}]", $crate::file!(), $crate::line!()); + log::debug!("[{}:{}]", $crate::file!(), $crate::line!()); }, ($val:expr $(,)?) => { @@ -772,8 +905,7 @@ pub macro dbg { // of temporaries - https://stackoverflow.com/a/48732525/1063961 match $val { tmp => { - $crate::rendy::println!("[{}:{}] {} = {:#?}", - core::file!(), core::line!(), core::stringify!($val), &tmp); + log::debug!("[{}:{}] {} = {:#?}", core::file!(), core::line!(), core::stringify!($val), &tmp); tmp } } @@ -797,34 +929,19 @@ pub fn _print(args: fmt::Arguments) { /// Clears the screen and if `mv` is set to true, resets the /// cursor position to `0`. pub fn clear_screen(mv: bool) { - DEBUG_RENDY.get().map(|l| l.lock_irq().clear(mv)); + if let Some(l) = DEBUG_RENDY.get() { + l.lock_irq().clear(mv) + } } pub fn backspace() { - DEBUG_RENDY.get().map(|l| l.lock_irq().backspace()); -} - -pub fn set_text_color(fg: u32, bg: u32) { - DEBUG_RENDY - .get() - .map(|l| l.lock_irq().color = ColorCode::new(fg, bg)); -} - -pub fn set_text_fg(fg: u32) { - DEBUG_RENDY.get().map(|l| l.lock_irq().color.0 = fg); -} - -pub fn set_text_bg(bg: u32) { - DEBUG_RENDY.get().map(|l| l.lock_irq().color.1 = bg); -} - -/// Resets the text foreground and background to their default values. -pub fn reset_default() { - set_text_color(DEFAULT_TEXT_FOREGROUND, DEFAULT_TEXT_BACKGROUND) + if let Some(l) = DEBUG_RENDY.get() { + l.lock_irq().backspace() + } } -/// Returns the terminal's resolution in the form of a `(horizontal_resolution, vertical_resolution)` -/// tuple. +/// Returns the terminal's resolution in the form of a `(horizontal_resolution, +/// vertical_resolution)` tuple. /// /// # Panics /// This function was called before the terminal was initialized. @@ -885,79 +1002,48 @@ pub fn get_cursor_position() -> (usize, usize) { /// * If the provided `x` position is greator then the amount of columns. /// * If the provided `y` position is greator then the amount of rows. pub fn set_cursor_position(x: usize, y: usize) { - DEBUG_RENDY - .get() - .map(|l| l.lock_irq().set_cursor_position(x, y)); -} - -pub fn set_cursor_visibility(yes: bool) { - DEBUG_RENDY - .get() - .map(|l| l.lock_irq().cursor_visibility = yes); -} - -/// Returns a tuple of the amount of `(rows, columns)` in the terminal. -/// -/// ## Panics -/// This function was called before the terminal was initialized. -pub fn get_term_info() -> (usize, usize) { - DEBUG_RENDY - .get() - .map(|l| { - let lock = l.lock_irq(); - (lock.rows, lock.cols) - }) - .expect("get_term_info: invoked before the terminal was initialized") -} - -/// ## Panics -/// This function was called before the terminal was initialized. -pub fn set_auto_flush(yes: bool) { - DEBUG_RENDY - .get() - .map(|e| e.lock_irq().set_auto_flush(yes)) - .expect("set_auto_flush: invoked before the terminal was initialized"); -} - -/// ## Panics -/// This function was called before the terminal was initialized. -pub fn double_buffer_flush() { - DEBUG_RENDY - .get() - .map(|e| e.lock_irq().double_buffer_flush()) - .expect("double_buffer_flush: invoked before the terminal was initialized"); + if let Some(l) = DEBUG_RENDY.get() { + l.lock_irq().set_cursor_position(x, y) + } } /// Force-unlocks the rendy to prevent a deadlock. /// -/// ## Saftey +/// ## Safety /// This method is not memory safe and should be only used when absolutely necessary. pub unsafe fn force_unlock() { - DEBUG_RENDY.get().map(|l| l.force_unlock()); + if let Some(l) = DEBUG_RENDY.get() { + l.force_unlock() + } } -pub fn init(framebuffer_tag: &LimineFramebuffer, cmdline: &CommandLine) { +pub fn init(fb_info: Framebuffer, cmdline: &CommandLine) { + let stride = fb_info.pitch() as usize; + let height = fb_info.height() as usize; + let bits_per_pixel = fb_info.bpp() as usize; + let byte_len = stride * height * (bits_per_pixel / 8); + let framebuffer_info = RendyInfo { - byte_len: framebuffer_tag.size(), - bits_per_pixel: framebuffer_tag.bpp as usize, - horizontal_resolution: framebuffer_tag.width as usize, - vertical_resolution: framebuffer_tag.height as usize, + byte_len, + bits_per_pixel, + horizontal_resolution: fb_info.width() as usize, + vertical_resolution: height, pixel_format: PixelFormat::BGR, - stride: framebuffer_tag.pitch as usize, + stride, - red_mask_shift: framebuffer_tag.red_mask_shift, - red_mask_size: framebuffer_tag.red_mask_size, + red_mask_shift: fb_info.red_mask_shift(), + red_mask_size: fb_info.red_mask_size(), - green_mask_shift: framebuffer_tag.green_mask_shift, - green_mask_size: framebuffer_tag.green_mask_size, + green_mask_shift: fb_info.green_mask_shift(), + green_mask_size: fb_info.green_mask_size(), - blue_mask_shift: framebuffer_tag.blue_mask_shift, - blue_mask_size: framebuffer_tag.blue_mask_size, + blue_mask_shift: fb_info.blue_mask_shift(), + blue_mask_size: fb_info.blue_mask_size(), }; let framebuffer = unsafe { core::slice::from_raw_parts_mut::( - framebuffer_tag.address.as_ptr().unwrap() as *mut u32, + fb_info.addr().cast::(), framebuffer_info.byte_len, ) }; diff --git a/src/aero_kernel/src/socket/ipv4.rs b/src/aero_kernel/src/socket/ipv4.rs new file mode 100644 index 00000000000..44e0893610d --- /dev/null +++ b/src/aero_kernel/src/socket/ipv4.rs @@ -0,0 +1,55 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +//! IPv4 or `AF_RAW` sockets. + +use alloc::sync::Arc; + +use aero_syscall::prelude::{IfReq, SIOCGIFINDEX}; + +use crate::arch::user_copy::UserRef; + +use crate::fs::inode::INodeInterface; +use crate::fs::Result; + +use crate::mem::paging::VirtAddr; + +pub struct Ipv4Socket {} + +impl Ipv4Socket { + pub fn new() -> Arc { + Arc::new(Self {}) + } +} + +impl INodeInterface for Ipv4Socket { + fn ioctl(&self, command: usize, arg: usize) -> Result { + match command { + SIOCGIFINDEX => { + let mut ifreq = unsafe { UserRef::::new(VirtAddr::new(arg as _)) }; + + let name = ifreq.name().unwrap(); + assert!(name == "eth0"); + + ifreq.data.ifindex = 1; // FIXME: Fill the actual interface index + Ok(0) + } + + _ => unimplemented!(), + } + } +} diff --git a/src/aero_kernel/src/socket/mod.rs b/src/aero_kernel/src/socket/mod.rs index 43382b6e667..81fbab5b26c 100644 --- a/src/aero_kernel/src/socket/mod.rs +++ b/src/aero_kernel/src/socket/mod.rs @@ -1,50 +1,81 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . +pub mod ipv4; +pub mod tcp; +// pub mod tcp2; +pub mod netlink; +pub mod udp; +pub mod unix; + +use aero_syscall::netlink::sockaddr_nl; +use aero_syscall::prelude::IfReq; use aero_syscall::*; use crate::mem::paging::VirtAddr; #[derive(Debug)] -pub enum SocketAddr<'a> { +pub enum SocketAddr { + Inet(SocketAddrInet), + Netlink(sockaddr_nl), + Unix(SocketAddrUnix), +} + +#[derive(Debug)] +pub enum SocketAddrRef<'a> { Unix(&'a SocketAddrUnix), INet(&'a SocketAddrInet), + // TODO: https://docs.huihoo.com/doxygen/linux/kernel/3.7/structsockaddr__nl.html + Netlink, } -impl<'a> SocketAddr<'a> { - pub fn from_family(address: VirtAddr, family: u32) -> Option { +impl<'a> SocketAddrRef<'a> { + pub fn from_family(address: VirtAddr, family: u32) -> Result { match family { - AF_UNIX => Some(SocketAddr::Unix(address.read_mut::()?)), - AF_INET => Some(SocketAddr::INet(address.read_mut::()?)), + AF_UNIX => Ok(SocketAddrRef::Unix(address.read_mut::()?)), + AF_INET => Ok(SocketAddrRef::INet(address.read_mut::()?)), + AF_NETLINK => Ok(SocketAddrRef::Netlink), - _ => None, + _ => Err(SyscallError::EINVAL), } } + pub fn from_ifreq(ifreq: &IfReq) -> Result { + // SAFETY??? + let family = unsafe { ifreq.data.addr.sa_family }; + SocketAddrRef::from_family( + VirtAddr::new(&unsafe { ifreq.data.addr } as *const _ as _), + family, + ) + } + /// Converts the socket address into a unix socket address. Returns [`None`] if /// the address is not a unix socket address. pub fn as_unix(&self) -> Option<&'a SocketAddrUnix> { match self { - SocketAddr::Unix(address) => Some(address), + SocketAddrRef::Unix(address) => Some(address), _ => None, } } -} -pub mod unix; + pub fn as_inet(&self) -> Option<&'a SocketAddrInet> { + match self { + SocketAddrRef::INet(addr) => Some(addr), + _ => None, + } + } +} diff --git a/src/aero_kernel/src/socket/netlink.rs b/src/aero_kernel/src/socket/netlink.rs new file mode 100644 index 00000000000..55240f2adbf --- /dev/null +++ b/src/aero_kernel/src/socket/netlink.rs @@ -0,0 +1,330 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +//! Netlink Sockets +//! +//! Netlink sockets are used for inter-process communication (IPC) between both the kernel and +//! userspace processes, and between different userspace processes, in a way similar to the Unix +//! domain sockets. +//! +//! Netlink is designed and used for transferring miscellaneous networking information between the +//! kernel space and userspace processes. Networking utilities, such as the `iproute2` family use +//! Netlink to communicate with the kernel from userspace. + +use aero_syscall::netlink::{MessageFlags, MessageType, RtAttrType}; +use aero_syscall::socket::{self, MessageHeader}; +use aero_syscall::{netlink, OpenFlags, AF_INET, AF_NETLINK, AF_UNSPEC}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use crabnet::network::Ipv4Addr; + +use crate::fs; +use crate::fs::inode::{FileType, INodeInterface, Metadata, PollFlags, PollTable}; +use crate::utils::sync::{Mutex, WaitQueue}; + +use super::SocketAddrRef; + +// TODO(andypython): can we use crabnet to construct netlink packets(?) +struct NetlinkBuilder { + buffer: Vec, +} + +impl NetlinkBuilder { + fn new() -> Self { + // crate::scheduler::get_scheduler().for_each_task(|task| { + // if task + // .executable + // .lock() + // .as_ref() + // .map(|x| x.absolute_path_str().contains("kit")) + // .unwrap_or_default() + // { + // task.enable_systrace(); + // } + // }); + + Self { buffer: Vec::new() } + } + + fn header(&mut self, header: &netlink::nlmsghdr) { + self.buffer.extend_from_slice(unsafe { + core::slice::from_raw_parts( + &header as *const _ as *const u8, + core::mem::size_of::(), + ) + }); + + self.buffer_align(); + } + + fn message(&mut self, message: &netlink::rtmsg) { + self.buffer.extend_from_slice(unsafe { + core::slice::from_raw_parts( + &message as *const _ as *const u8, + core::mem::size_of::(), + ) + }); + + self.buffer_align(); + } + + fn rtattr(&mut self, ty: RtAttrType, data: T) { + let rta_len = netlink::rta_length(core::mem::size_of::() as u32); + + let attr = netlink::rtattr { + rta_len: rta_len.try_into().unwrap(), + rta_type: ty, + }; + + let padding = rta_len as usize - core::mem::size_of::(); + + self.buffer.extend_from_slice(unsafe { + core::slice::from_raw_parts( + &attr as *const _ as *const u8, + core::mem::size_of::(), + ) + }); + + self.buffer.extend_from_slice(unsafe { + core::slice::from_raw_parts(&data as *const _ as *const u8, core::mem::size_of::()) + }); + + self.buffer.resize(self.buffer.len() + padding, 0); + self.buffer_align(); + } + + /// Aligns the buffer to the netlink message alignment. + fn buffer_align(&mut self) { + let aligned_len = netlink::nlmsg_align(self.buffer.len() as u32); + + // Resize will not truncate the buffer since [`nlmsg_align`]` only rounds up. + self.buffer.resize(aligned_len as usize, 0); + } + + fn build(self) -> Vec { + let mut buffer = self.buffer; + + let msg_len = buffer.len(); + let msg_hdr = unsafe { &mut *buffer.as_mut_ptr().cast::() }; + + msg_hdr.nlmsg_len = msg_len as u32; + buffer + } +} + +pub struct NetLinkSocket { + recv_queue: Mutex>>, + recv_wq: WaitQueue, +} + +impl NetLinkSocket { + pub fn new() -> Arc { + Arc::new(Self { + recv_queue: Mutex::new(Vec::new()), + recv_wq: WaitQueue::new(), + }) + } + + fn validate_message<'a, T>(header: &'a netlink::nlmsghdr, payload: &'a [u8]) -> &'a T { + let hdr_len = core::mem::size_of::() as u32; + let msg_len = core::mem::size_of::() as u32; + + // TODO(andypython): send an error message instead of panicking. + assert!(header.nlmsg_len == hdr_len + msg_len); + + // FIXME(andypython): use bytemuck to cast the payload to T. + unsafe { &*payload.as_ptr().cast::() } + } + + fn send_route_packet(&self, header: &netlink::nlmsghdr) { + let mut builder = NetlinkBuilder::new(); + + builder.header(&netlink::nlmsghdr { + nlmsg_type: MessageType::RtmNewRoute, + nlmsg_flags: MessageFlags::MULTI, + nlmsg_seq: header.nlmsg_seq, + nlmsg_pid: 0, + nlmsg_len: 0, + }); + + builder.message(&netlink::rtmsg { + rtm_family: AF_INET as u8, + rtm_dst_len: 0, // FIXME + rtm_src_len: 0, + rtm_tos: 0, + rtm_table: netlink::RT_TABLE_MAIN, + + rtm_protocol: 0, + rtm_scope: 0, + rtm_type: 0, + rtm_flags: 0, + }); + + builder.rtattr(RtAttrType::Table, netlink::RT_TABLE_MAIN); + + // Qemu SLIRP + builder.rtattr(RtAttrType::Dst, Ipv4Addr::new(10, 0, 2, 15)); + builder.rtattr(RtAttrType::Gateway, Ipv4Addr::new(10, 0, 2, 2)); + + self.recv_queue.lock().push(builder.build()); + self.recv_wq.notify(); + } + + fn get_route(&self, header: &netlink::nlmsghdr, payload: &[u8]) { + assert!(header + .nlmsg_flags + .contains(MessageFlags::REQUEST | MessageFlags::DUMP)); + + let payload = Self::validate_message::(header, payload); + let rtgen_family = payload.rtgen_family as u32; + + assert!(rtgen_family == AF_UNSPEC || rtgen_family == AF_NETLINK); + + self.send_route_packet(header); + } +} + +impl INodeInterface for NetLinkSocket { + fn metadata(&self) -> fs::Result { + Ok(Metadata::with_file_type(FileType::Socket)) + } + + fn bind(&self, _addr: SocketAddrRef, _len: usize) -> fs::Result<()> { + Ok(()) + } + + fn connect(&self, _address: SocketAddrRef, _length: usize) -> fs::Result<()> { + unimplemented!() + } + + fn read_at(&self, _flags: OpenFlags, _offset: usize, _buffer: &mut [u8]) -> fs::Result { + unimplemented!() + } + + fn write_at(&self, _offset: usize, _buffer: &[u8]) -> fs::Result { + unimplemented!() + } + + fn recv( + &self, + fd_flags: OpenFlags, + message_hdr: &mut MessageHeader, + flags: socket::MessageFlags, + ) -> fs::Result { + // FIXME(andypython): All of the message header and iovec logic should be moved to + // syscall::net::recvmsg() instead. + + if let Some(addr) = message_hdr.name_mut::() { + *addr = netlink::sockaddr_nl { + nl_family: AF_NETLINK, + nl_pad: 0, + nl_pid: 0, + nl_groups: 0, + }; + } + + let mut queue = self + .recv_wq + .wait(fd_flags.into(), &self.recv_queue, |queue| !queue.is_empty())?; + + let mut bytes_copied = 0; + dbg!(message_hdr.iovecs_mut()); + let mut iovecs = message_hdr.iovecs_mut().to_vec(); + + while let Some(data) = queue.pop() { + if let Some((index, ref mut iovec)) = iovecs + .iter_mut() + .enumerate() + .find(|(_, iovec)| iovec.len() >= data.len()) + { + let iovec = iovec.as_slice_mut(); + assert!(iovec.len() >= data.len()); + + let copy = core::cmp::min(iovec.len(), data.len()); + iovec[..copy].copy_from_slice(&data[..copy]); + + bytes_copied += copy; + iovecs.remove(index); + } else if flags.contains(socket::MessageFlags::TRUNC) && bytes_copied == 0 { + message_hdr.flags = socket::MessageFlags::TRUNC.bits() as i32; + return Ok(data.len()); + } else { + unimplemented!() + } + } + + Ok(bytes_copied) + } + + fn send( + &self, + message_hdr: &mut MessageHeader, + flags: socket::MessageFlags, + ) -> fs::Result { + log::warn!("netlink::send(flags={flags:?})"); + + // FIXME(andypython): figure out the message header stuff... + let data = message_hdr + .iovecs() + .iter() + .flat_map(|e| e.as_slice()) + .copied() + .collect::>(); + + let hdr_size = core::mem::size_of::(); + + let mut offset = 0; + + while offset + hdr_size <= data.len() { + let header = unsafe { &*(data.as_ptr().cast::().byte_add(offset)) }; + let payload = &data[offset + hdr_size..]; + + match header.nlmsg_type { + MessageType::Done => break, + MessageType::Error => { + unimplemented!("netlink::send: error message received"); + } + + MessageType::RtmGetRoute => self.get_route(header, payload), + + ty => unimplemented!("netlink::send: unknown message type {ty:?}"), + } + + offset += header.nlmsg_len as usize; + } + + Ok(data.len()) + } + + fn poll(&self, _table: Option<&mut PollTable>) -> fs::Result { + unimplemented!() + } + + fn get_peername(&self) -> fs::Result { + unimplemented!() + } + + fn get_sockname(&self) -> fs::Result { + // TODO(andypython): fill in `nl_groups` and `nl_pid`. + Ok(super::SocketAddr::Netlink(netlink::sockaddr_nl { + nl_family: AF_NETLINK, + nl_pad: 0, + nl_pid: 0, + nl_groups: 0, + })) + } +} diff --git a/src/aero_kernel/src/socket/tcp.rs b/src/aero_kernel/src/socket/tcp.rs new file mode 100644 index 00000000000..f135fe7d3fa --- /dev/null +++ b/src/aero_kernel/src/socket/tcp.rs @@ -0,0 +1,260 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::socket::{MessageFlags, MessageHeader}; +use aero_syscall::{InAddr, OpenFlags, SocketAddrInet, AF_INET}; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; + +use crabnet::network::Ipv4Addr; +use spin::Once; + +use crabnet::data_link::{Eth, EthType, MacAddr}; +use crabnet::transport::{Tcp, TcpOptions}; +use crabnet_tcp::{Address, Error as TcpError, Packet as TcpPacket, State}; + +use crate::fs::inode::{FileType, INodeInterface, Metadata, PollFlags, PollTable}; +use crate::fs::{self, FileSystemError}; +use crate::net; +use crate::net::shim::PacketSend; +use crate::net::{tcp, NetworkDevice}; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueFlags}; + +// ./aero.py -- -netdev user,id=mynet0 -device e1000,netdev=mynet0,id=ck_nic0 -object +// filter-dump,id=mynet0,netdev=mynet0,file=qemulog.log + +struct DeviceShim(Arc); + +impl crabnet_tcp::NetworkDevice for DeviceShim { + fn ip(&self) -> Ipv4Addr { + self.0.ip() + } + + fn send(&self, packet: TcpPacket, _handle: crabnet_tcp::RetransmitHandle) { + // TODO(andypython): Handle TCP retransmission here. + let eth = Eth::new(MacAddr::NULL, self.0.mac(), EthType::Ip); + (eth / packet.ip / packet.tcp / packet.options / packet.payload).send(); + } + + fn remove_retransmit(&self, _seq_number: u32) { + // TODO(andypython): Handle TCP retransmission here. + } +} + +pub struct TcpSocket { + tcp: Mutex>>, + wq: WaitQueue, + sref: Weak, + peer: Once, +} + +impl TcpSocket { + pub fn new() -> Arc { + Arc::new_cyclic(|sref| Self { + tcp: Mutex::new(None), + wq: WaitQueue::new(), + sref: sref.clone(), + peer: Once::new(), + }) + } + + pub fn on_packet(&self, tcp: &Tcp, options: &TcpOptions, payload: &[u8]) { + if let Some(socket) = self.tcp.lock_irq().as_mut() { + // Ignore any invalid TCP options. + let options = options.iter().filter_map(Result::ok).collect::>(); + + socket.on_packet(tcp, &options, payload); + self.wq.notify_all(); + } + } + + fn sref(&self) -> Arc { + self.sref.upgrade().unwrap() + } + + pub fn do_recv(&self, flags: OpenFlags, buf: &mut [u8]) -> Result { + let mut tcp = self.tcp.lock_irq(); + let socket = tcp.as_mut().ok_or(FileSystemError::NotConnected)?; + + match socket.recv(buf) { + Ok(bytes_read) => Ok(bytes_read), + + Err(TcpError::WouldBlock) if flags.is_nonblock() => Err(FileSystemError::WouldBlock), + Err(TcpError::WouldBlock) => { + drop(tcp); + + let mut socket = self.wq.wait(flags.into(), &self.tcp, |tcp| { + tcp.as_ref() + .is_none_or(|socket| !socket.recv_queue.is_empty()) + })?; + + if let Some(socket) = socket.as_mut() { + Ok(socket.recv(buf).unwrap()) + } else { + Err(FileSystemError::NotConnected) + } + } + + Err(err) => unreachable!("{err:?}"), + } + } + + pub fn send(&self, buf: &[u8]) -> Result { + let mut tcp = self.tcp.lock_irq(); + let socket = tcp.as_mut().ok_or(FileSystemError::NotConnected)?; + + let bytes_written = socket.send(buf).unwrap(); + Ok(bytes_written) + } +} + +impl INodeInterface for TcpSocket { + fn connect(&self, address: super::SocketAddrRef, _length: usize) -> crate::fs::Result<()> { + { + let mut tcp = self.tcp.lock_irq(); + assert!(tcp.is_none(), "connect: socket is already initialized"); + + let port = tcp::alloc_ephemeral_port(self.sref()).unwrap(); + + let addr = address.as_inet().ok_or(FileSystemError::NotSupported)?; + self.peer.call_once(|| addr.clone()); + + if addr.addr() == Ipv4Addr::LOOPBACK.0 { + return Err(FileSystemError::NotSupported); + } + + let addr = Address::new(port, addr.port(), addr.addr().into()); + + let device = Arc::new(DeviceShim(net::default_device())); + let socket = crabnet_tcp::Socket::connect(device, addr); + + *tcp = Some(socket); + } + + // FIXME: connect() should pass the fd. + let _ = self.wq.wait(WaitQueueFlags::empty(), &self.tcp, |x| { + x.as_ref().unwrap().state() == State::Established + }); + + Ok(()) + } + + #[inline] + fn metadata(&self) -> Result { + Ok(Metadata::with_file_type(FileType::Socket)) + } + + #[inline] + fn read_at( + &self, + flags: OpenFlags, + _offset: usize, + buf: &mut [u8], + ) -> Result { + self.do_recv(flags, buf) + } + + #[inline] + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + self.send(buf) + } + + fn send(&self, message_hdr: &mut MessageHeader, _flags: MessageFlags) -> fs::Result { + let data = message_hdr + .iovecs() + .iter() + .flat_map(|e| e.as_slice()) + .copied() + .collect::>(); + + let mut tcp = self.tcp.lock_irq(); + let socket = tcp.as_mut().ok_or(FileSystemError::NotSupported)?; + + // TODO: handle fragmentation in crabnet_tcp + for chunk in data.chunks(1460) { + socket.send(chunk).expect("failed to send data"); + } + + // -netdev user,id=mynet0,net=192.168.1.0/24,dhcpstart=192.168.1.128,hostfwd=tcp::4444-:80 + // -device e1000,netdev=mynet0,id=ck_nic0 -object + // filter-dump,id=mynet0,netdev=user,file=qemulog.log + + Ok(data.len()) + } + + fn get_peername(&self) -> fs::Result { + if let Some(peer) = self.peer.get() { + let addr = super::SocketAddr::Inet(peer.clone()); + Ok(addr) + } else { + Err(FileSystemError::NotConnected) + } + } + + fn get_sockname(&self) -> fs::Result { + if let Some(socket) = self.tcp.lock().as_mut() { + // FIXME: + let addr = SocketAddrInet { + family: AF_INET, + port: socket.addr.src_port.into(), + sin_addr: InAddr { addr: 0 }, + padding: [0; 8], + }; + + Ok(super::SocketAddr::Inet(addr)) + } else { + Err(FileSystemError::NotConnected) + } + } + + fn recv( + &self, + fd_flags: OpenFlags, + message_hdr: &mut MessageHeader, + _flags: MessageFlags, + ) -> fs::Result { + Ok(message_hdr + .iovecs_mut() + .iter_mut() + .map(|iovec| { + let iovec = iovec.as_slice_mut(); + self.do_recv(fd_flags, iovec).unwrap() + }) + .sum::()) + } + + fn poll(&self, table: Option<&mut PollTable>) -> fs::Result { + if let Some(table) = table { + table.insert(&self.wq); + } + + let mut flags = PollFlags::empty(); + let mut tcp = self.tcp.lock_irq(); + + if let Some(socket) = tcp.as_mut() { + assert_ne!(socket.state(), State::Closed); + + flags |= PollFlags::OUT; + + if !socket.recv_queue.is_empty() { + flags |= PollFlags::IN; + } + } + + Ok(flags) + } +} diff --git a/src/aero_kernel/src/socket/udp.rs b/src/aero_kernel/src/socket/udp.rs new file mode 100644 index 00000000000..83934c8484c --- /dev/null +++ b/src/aero_kernel/src/socket/udp.rs @@ -0,0 +1,295 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::prelude::{IfReq, SIOCGIFHWADDR, SIOCSIFADDR, SIOCSIFNETMASK}; +use aero_syscall::socket::{MessageFlags, MessageHeader}; +use aero_syscall::{OpenFlags, SocketAddrInet}; +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; +use spin::Once; + +use crate::arch::user_copy::UserRef; +use crate::fs::cache::DirCacheItem; +use crate::fs::file_table::FileHandle; +use crate::fs::inode::{FileType, INodeInterface, Metadata, PollFlags}; +use crate::fs::{self, FileSystemError}; +use crate::mem::paging::VirtAddr; +use crate::net::udp::{self, UdpHandler}; +use crate::net::{self}; +use crate::utils::sync::{Mutex, WaitQueue}; + +use super::SocketAddrRef; + +use crabnet::data_link::{Eth, EthType, MacAddr}; +use crabnet::network::{Ipv4, Ipv4Addr, Ipv4Type}; +use crabnet::transport::Udp; + +#[derive(Default)] +enum SocketState { + /// The socket is not connected. + #[default] + Disconnected, + Connected(SocketAddrInet), +} + +#[derive(Default)] +struct UdpSocketInner { + /// The address that the socket has been bound to. + address: Option, + state: SocketState, + incoming: Vec>, +} + +pub struct UdpSocket { + inner: Mutex, + wq: WaitQueue, + handle: Once>, + + sref: Weak, +} + +impl UdpSocket { + pub fn new() -> Arc { + Arc::new_cyclic(|sref| Self { + wq: WaitQueue::new(), + handle: Once::new(), + + inner: Mutex::new(Default::default()), + sref: sref.clone(), + }) + } + + fn sref(&self) -> Arc { + self.sref.upgrade().unwrap() + } + + fn set_state(&self, state: SocketState) { + self.inner.lock_irq().state = state; + } + + fn set_addr(&self, addr: SocketAddrInet) { + self.inner.lock_irq().address = Some(addr); + } + + fn src_port(&self) -> Option { + self.inner + .lock_irq() + .address + .as_ref() + .map(|e| e.port.to_native()) + } + + fn dest(&self) -> SocketAddrInet { + match &self.inner.lock_irq().state { + SocketState::Connected(addr) => addr.clone(), + _ => unreachable!(), + } + } + + pub fn is_non_block(&self) -> bool { + self.handle + .get() + .expect("inet: not bound to an fd") + .flags() + .contains(OpenFlags::O_NONBLOCK) + } +} + +impl INodeInterface for UdpSocket { + fn open(&self, handle: Arc) -> fs::Result> { + self.handle.call_once(|| handle); + Ok(None) + } + + fn metadata(&self) -> fs::Result { + Ok(Metadata { + id: 0, + file_type: FileType::Socket, + size: 0, + children_len: 0, + }) + } + + fn bind(&self, address: super::SocketAddrRef, _length: usize) -> fs::Result<()> { + let address = address.as_inet().ok_or(FileSystemError::NotSupported)?; + + self.set_addr(address.clone()); + udp::bind(address.port.to_native(), self.sref()); + Ok(()) + } + + fn connect(&self, address: super::SocketAddrRef, _length: usize) -> fs::Result<()> { + let address = address.as_inet().ok_or(FileSystemError::NotSupported)?; + + let host_addr = Ipv4Addr::from(address.sin_addr.addr.to_be_bytes()); + udp::connect(host_addr, address.port.to_native()); + + self.set_state(SocketState::Connected(address.clone())); + Ok(()) + } + + fn send(&self, message_hdr: &mut MessageHeader, _flags: MessageFlags) -> fs::Result { + let name = message_hdr + .name_mut::() + .cloned() + .unwrap_or_else(|| self.dest()); + + let dest_port = name.port.to_native(); + let dest_ip = Ipv4Addr::from(name.addr()); + + let src_port; + + if let Some(port) = self.src_port() { + src_port = port; + } else { + src_port = udp::alloc_ephemeral_port(self.sref()).ok_or(FileSystemError::WouldBlock)?; + log::debug!("Inet::send(): allocated ephemeral port {}", src_port); + } + + let data = message_hdr + .iovecs() + .iter() + .flat_map(|e| e.as_slice()) + .copied() + .collect::>(); + + // FIXME: loopback + if dest_ip == Ipv4Addr::LOOPBACK { + log::debug!("looback moments :)"); + return Err(FileSystemError::NotSupported); + // return Ok(data.len()); + } + + use crate::net::shim::PacketSend; + + let eth = Eth::new(MacAddr::NULL, MacAddr::NULL, EthType::Ip); + let ipv4 = Ipv4::new(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, Ipv4Type::Udp); + let udp = Udp::new(src_port, dest_port); + let packet = eth / ipv4 / udp / data.as_slice(); + + packet.send(); + Ok(data.len()) + } + + fn recv( + &self, + fd_flags: OpenFlags, + message_hdr: &mut MessageHeader, + _flags: MessageFlags, + ) -> fs::Result { + // assert!(flags.is_empty()); + + let mut this = self + .wq + .wait(fd_flags.into(), &self.inner, |e| !e.incoming.is_empty())?; + + let packet = this.incoming.pop().expect("recv: someone was greedy"); + + let mut data = packet.as_slice().to_vec(); + + Ok(message_hdr + .iovecs_mut() + .iter_mut() + .map(|iovec| { + let iovec = iovec.as_slice_mut(); + let size = core::cmp::min(iovec.len(), data.len()); + iovec[..size].copy_from_slice(&data.drain(..size).collect::>()); + size + }) + .sum::()) + } + + fn ioctl(&self, command: usize, arg: usize) -> fs::Result { + match command { + SIOCGIFHWADDR => { + let mut ifreq = unsafe { UserRef::::new(VirtAddr::new(arg as _)) }; + + let name = ifreq.name().ok_or(FileSystemError::InvalidPath)?; + assert!(name == "eth0"); + + let hwaddr = unsafe { + core::slice::from_raw_parts_mut( + ifreq.data.addr.sa_data.as_mut_ptr(), + MacAddr::ADDR_SIZE, + ) + }; + + let mac_addr = net::default_device().mac(); + hwaddr.copy_from_slice(mac_addr.0.as_slice()); + Ok(0) + } + + SIOCSIFADDR => { + let ifreq = unsafe { UserRef::::new(VirtAddr::new(arg as _)) }; + let socket = SocketAddrRef::from_ifreq(&ifreq) + .map_err(|_| FileSystemError::NotSupported)? + .as_inet() + .ok_or(FileSystemError::NotSupported)?; + + let name = ifreq.name().ok_or(FileSystemError::InvalidPath)?; + + // FIXME: + assert!(name == "eth0"); + + let device = net::default_device(); + device.set_ip(Ipv4Addr::from(socket.addr())); + Ok(0) + } + + SIOCSIFNETMASK => { + let ifreq = unsafe { UserRef::::new(VirtAddr::new(arg as _)) }; + let socket = SocketAddrRef::from_ifreq(&ifreq) + .map_err(|_| FileSystemError::NotSupported)? + .as_inet() + .ok_or(FileSystemError::NotSupported)?; + + let name = ifreq.name().ok_or(FileSystemError::InvalidPath)?; + + // FIXME: + assert!(name == "eth0"); + + let device = net::default_device(); + device.set_subnet_mask(Ipv4Addr::from(socket.addr())); + + Ok(0) + } + + _ => unreachable!("inet::ioctl(): unknown command {command}"), + } + } + + fn poll(&self, table: Option<&mut fs::inode::PollTable>) -> fs::Result { + if let Some(table) = table { + table.insert(&self.wq); + } + + let mut flags = PollFlags::OUT; + + if !self.inner.lock_irq().incoming.is_empty() { + flags |= PollFlags::IN; + } + + Ok(flags) + } +} + +impl UdpHandler for UdpSocket { + fn recv(&self, _udp: &Udp, payload: &[u8]) { + self.inner.lock_irq().incoming.push(payload.to_vec()); + self.wq.notify_all(); + } +} diff --git a/src/aero_kernel/src/socket/unix.rs b/src/aero_kernel/src/socket/unix.rs index 9c0832b5a6a..749cfce3e46 100644 --- a/src/aero_kernel/src/socket/unix.rs +++ b/src/aero_kernel/src/socket/unix.rs @@ -1,44 +1,47 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use aero_syscall::{SocketAddrUnix, SyscallError}; - -use aero_syscall::socket::MessageHeader; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::{OpenFlags, SocketAddrUnix, SyscallError, AF_UNIX}; + +use aero_syscall::socket::{MessageFlags, MessageHeader}; use alloc::collections::VecDeque; use alloc::sync::{Arc, Weak}; use alloc::vec::Vec; +use crate::arch::user_copy::UserRef; use crate::fs; -use crate::fs::inode::*; +use crate::fs::cache::DirCacheItem; +use crate::fs::file_table::FileHandle; +use crate::fs::inode::{DirEntry, FileType, INodeInterface, Metadata, PollFlags, PollTable}; use crate::fs::{FileSystemError, Path}; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::mem::paging::VirtAddr; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueFlags}; -use super::SocketAddr; +use super::SocketAddrRef; -fn path_from_unix_sock<'sock>(address: &'sock SocketAddrUnix) -> fs::Result<&'sock Path> { +fn path_from_unix_sock(address: &SocketAddrUnix) -> fs::Result<&Path> { // The abstract namespace socket allows the creation of a socket // connection which does not require a path to be created. - let abstrat_namespaced = address.path[0] == 0; - assert!(!abstrat_namespaced); + let abstract_namespaced = address.path[0] == 0; + assert!(!abstract_namespaced); + assert!(address.path[1] != 0, "unnamed UNIX socket"); let path_len = address .path @@ -76,14 +79,19 @@ impl MessageQueue { } pub fn read(&mut self, buffer: &mut [u8]) -> usize { - log::debug!("MessageQueue::read(): {:?}", self.messages); - - if let Some(message) = self.messages.pop_front() { + if let Some(message) = self.messages.front_mut() { let message_len = message.data.len(); - assert!(buffer.len() >= message_len); + let size = core::cmp::min(buffer.len(), message_len); + + buffer[..size].copy_from_slice(&message.data[..size]); + + if size < message_len { + message.data.drain(..size); + return size; + } - buffer[..message_len].copy_from_slice(message.data.as_slice()); - message_len + self.messages.pop_front(); + size } else { unreachable!("MessageQueue::read() called when queue is empty"); } @@ -92,8 +100,6 @@ impl MessageQueue { pub fn write(&mut self, buffer: &[u8]) { let message = Message::new(buffer.to_vec()); self.messages.push_back(message); - - log::debug!("MessageQueue::write(): {:?}", self.messages); } } @@ -104,8 +110,7 @@ pub struct AcceptQueue { impl AcceptQueue { /// # Parameters - /// * `backlog`: The maximum number of pending connections that the - /// queue can hold. + /// * `backlog`: The maximum number of pending connections that the queue can hold. pub fn new(backlog: usize) -> Self { Self { sockets: VecDeque::with_capacity(backlog), @@ -113,11 +118,6 @@ impl AcceptQueue { } } - /// Returns the number of pending connections in the queue. - pub fn len(&self) -> usize { - self.sockets.len() - } - /// Returns `true` if the queue contains no pending connections. pub fn is_empty(&self) -> bool { self.sockets.is_empty() @@ -171,6 +171,13 @@ impl UnixSocketState { fn is_connected(&self) -> bool { matches!(self, Self::Connected(_)) } + + fn queue(&mut self) -> Option<&mut AcceptQueue> { + match self { + Self::Listening(q) => Some(q), + _ => None, + } + } } #[derive(Default)] @@ -184,7 +191,7 @@ struct UnixSocketInner { pub struct UnixSocket { inner: Mutex, buffer: Mutex, - wq: BlockQueue, + wq: WaitQueue, weak: Weak, } @@ -194,11 +201,27 @@ impl UnixSocket { inner: Mutex::new(UnixSocketInner::default()), buffer: Mutex::new(MessageQueue::default()), - wq: BlockQueue::new(), + wq: WaitQueue::new(), weak: weak.clone(), }) } + pub fn connect_pair(a: &DirCacheItem, b: &DirCacheItem) -> fs::Result<()> { + let a = a + .inode() + .downcast_arc::() + .ok_or(FileSystemError::NotSocket)?; + + let b = b + .inode() + .downcast_arc::() + .ok_or(FileSystemError::NotSocket)?; + + a.inner.lock_irq().state = UnixSocketState::Connected(b.clone()); + b.inner.lock_irq().state = UnixSocketState::Connected(a); + Ok(()) + } + pub fn sref(&self) -> Arc { self.weak.upgrade().unwrap() } @@ -214,11 +237,17 @@ impl INodeInterface for UnixSocket { }) } - fn read_at(&self, _offset: usize, user_buffer: &mut [u8]) -> fs::Result { - let mut buffer = self.wq.block_on(&self.buffer, |e| !e.is_empty())?; - - let read = buffer.read(user_buffer); - Ok(read) + fn read_at( + &self, + flags: OpenFlags, + _offset: usize, + user_buffer: &mut [u8], + ) -> fs::Result { + let mut buf = self + .wq + .wait(flags.into(), &self.buffer, |e| !e.is_empty())?; + + Ok(buf.read(user_buffer)) } fn write_at(&self, _offset: usize, buffer: &[u8]) -> fs::Result { @@ -229,7 +258,7 @@ impl INodeInterface for UnixSocket { }; peer.buffer.lock_irq().write(buffer); - peer.wq.notify_complete(); + peer.wq.notify_all(); Ok(buffer.len()) } @@ -254,7 +283,7 @@ impl INodeInterface for UnixSocket { } } - fn bind(&self, address: SocketAddr, _length: usize) -> fs::Result<()> { + fn bind(&self, address: SocketAddrRef, _length: usize) -> fs::Result<()> { let address = address.as_unix().ok_or(FileSystemError::NotSupported)?; let path = path_from_unix_sock(address)?; @@ -271,7 +300,7 @@ impl INodeInterface for UnixSocket { Ok(()) } - fn connect(&self, address: SocketAddr, _length: usize) -> fs::Result<()> { + fn connect(&self, address: SocketAddrRef, _length: usize) -> fs::Result<()> { let address = address.as_unix().ok_or(FileSystemError::NotSupported)?; let path = path_from_unix_sock(address)?; let socket = fs::lookup_path(path)?; @@ -290,27 +319,30 @@ impl INodeInterface for UnixSocket { }; queue.push(self.sref()).unwrap(); - target.wq.notify_complete(); + target.wq.notify_all(); core::mem::drop(itarget); // release the lock - let _ = self.wq.block_on(&self.inner, |e| e.state.is_connected()); + // FIXME: connect() should pass fd. + let _ = self.wq.wait(WaitQueueFlags::empty(), &self.inner, |e| { + e.state.is_connected() + })?; Ok(()) } - fn accept(&self, _address: Option<&mut SocketAddr>) -> fs::Result> { - let mut inner = self.inner.lock_irq(); + fn accept(&self, address: Option<(VirtAddr, &mut u32)>) -> fs::Result> { + // TODO: accept + let mut inner = self.wq.wait(WaitQueueFlags::empty(), &self.inner, |e| { + e.state.queue().is_some_and(|x| !x.is_empty()) + })?; - let queue = match &mut inner.state { - UnixSocketState::Listening(queue) => queue, - _ => return Err(FileSystemError::ConnectionRefused), - }; - - if queue.len() == 0 { - return Err(FileSystemError::WouldBlock); - } + let queue = inner + .state + .queue() + .ok_or(FileSystemError::ConnectionRefused)?; let peer = queue.pop().expect("UnixSocket::accept(): backlog is empty"); let sock = Self::new(); + sock.inner.lock_irq().address.clone_from(&inner.address); { let mut sock_inner = sock.inner.lock_irq(); @@ -322,56 +354,119 @@ impl INodeInterface for UnixSocket { peer_data.state = UnixSocketState::Connected(sock.clone()); } - peer.wq.notify_complete(); + // THIS SHOULD NOT BE DONE HERE + if let Some((address, length)) = address { + let mut address = unsafe { UserRef::new(address) }; + + if let Some(paddr) = inner.address.as_ref() { + *address = paddr.clone(); + } else { + *address = SocketAddrUnix::default(); + address.family = AF_UNIX; + } + + // THIS IS WRONG use addr.name_len() + offset_of!(sockaddr_un, path) + *length = core::mem::size_of::() as u32; + } + + peer.wq.notify_all(); Ok(sock) } - fn recv(&self, header: &mut MessageHeader) -> fs::Result { - let inner = self.inner.lock_irq(); + fn recv( + &self, + fd_flags: OpenFlags, + header: &mut MessageHeader, + flags: MessageFlags, + ) -> fs::Result { + // assert!(flags.is_empty()); - log::trace!( - "UnixSocket::recv(): expecting a max of {} bytes", - header.iovecs().iter().map(|e| e.len()).sum::(), - ); + let inner = self.inner.lock_irq(); let peer = match &inner.state { UnixSocketState::Connected(peer) => peer, _ => return Err(FileSystemError::NotConnected), }; - let mut buffer = self.wq.block_on(&self.buffer, |e| !e.is_empty())?; + let mut buffer = self + .wq + .wait(fd_flags.into(), &self.buffer, |e| !e.is_empty())?; - header - .name_mut::() - .map(|e| *e = peer.inner.lock_irq().address.as_ref().cloned().unwrap()); + if let Some(addr) = header.name_mut::() { + *addr = peer.inner.lock_irq().address.as_ref().cloned().unwrap(); + } Ok(header .iovecs_mut() .iter_mut() - .map(|iovec| buffer.read(iovec.as_mut_slice())) + .map(|iovec| buffer.read(iovec.as_slice_mut())) .sum::()) } + fn send(&self, header: &mut MessageHeader, _flags: MessageFlags) -> fs::Result { + // FIXME(andyython): figure out the message header stuff... + let data = header + .iovecs() + .iter() + .flat_map(|e| e.as_slice()) + .copied() + .collect::>(); + + self.write_at(0, &data) + } + fn poll(&self, table: Option<&mut PollTable>) -> fs::Result { - table.map(|e| e.insert(&self.wq)); + let buffer = self.buffer.lock_irq(); + let inner = self.inner.lock_irq(); + + if let Some(e) = table { + e.insert(&self.wq) + } let mut events = PollFlags::OUT; - let inner = self.inner.lock_irq(); - match &inner.state { - UnixSocketState::Listening(queue) => { - if !queue.is_empty() { - events.insert(PollFlags::IN); - } + if let UnixSocketState::Listening(queue) = &inner.state { + if !queue.is_empty() { + events.insert(PollFlags::IN); + return Ok(events); } - - _ => {} } - if !self.buffer.lock_irq().is_empty() { + if !buffer.is_empty() { events.insert(PollFlags::IN); } Ok(events) } + + fn shutdown(&self, how: usize) -> fs::Result<()> { + log::warn!("shutdown how={how}"); + Ok(()) + } + + fn get_sockname(&self) -> fs::Result { + let inner = self.inner.lock_irq(); + let address = inner.address.as_ref().cloned().unwrap_or(SocketAddrUnix { + family: AF_UNIX, + path: [0; 108], + }); + + Ok(super::SocketAddr::Unix(address.clone())) + } + + fn get_peername(&self) -> fs::Result { + let inner = self.inner.lock_irq(); + let peer = match &inner.state { + UnixSocketState::Connected(peer) => peer, + _ => return Err(FileSystemError::NotConnected), + }; + + let peer = peer.inner.lock_irq(); + let address = peer.address.as_ref().cloned().unwrap_or(SocketAddrUnix { + family: AF_UNIX, + path: [0; 108], + }); + + Ok(super::SocketAddr::Unix(address.clone())) + } } diff --git a/src/aero_kernel/src/syscall/fs.rs b/src/aero_kernel/src/syscall/fs.rs index 7ad1d0fbf8f..415ed0d3d30 100644 --- a/src/aero_kernel/src/syscall/fs.rs +++ b/src/aero_kernel/src/syscall/fs.rs @@ -1,77 +1,119 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::fmt; + +use aero_syscall::prelude::*; use aero_syscall::signal::SigProcMask; -use aero_syscall::{prelude::*, TimeSpec}; -use aero_syscall::{OpenFlags, Stat, SyscallError}; +use aero_syscall::{AtFlags, OpenFlags, Stat, TimeSpec, AT_FDCWD}; +use alloc::sync::{Arc, Weak}; +use crate::fs::cache::{self, DirCacheImpl}; use crate::fs::epoll::EPoll; use crate::fs::eventfd::EventFd; -use crate::fs::file_table::DuplicateHint; +use crate::fs::file_table::{DuplicateHint, FileHandle}; use crate::fs::inode::{DirEntry, PollTable}; use crate::fs::pipe::Pipe; -use crate::fs::{self, lookup_path, LookupMode}; +use crate::fs::{self, LookupMode}; +use crate::syscall::SysArg; use crate::userland::scheduler; use crate::fs::Path; -#[syscall] -pub fn write(fd: usize, buffer: &[u8]) -> Result { - let handle = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; +#[derive(Debug, Copy, Clone)] +pub struct FileDescriptor(usize); + +impl FileDescriptor { + /// Returns the file handle associated with this file descriptor. + /// + /// ## Errors + /// * `EBADFD`: The file descriptor is not a valid open file descriptor. + pub fn handle(&self) -> aero_syscall::Result> { + scheduler::current_thread() + .file_table + .get_handle(self.0) + .ok_or(SyscallError::EBADFD) + } +} + +impl fmt::Display for FileDescriptor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Ok(file_handle) = self.handle() { + let path = file_handle.inode.absolute_path(); + write!(f, "{{ {} -> {} }}", self.0, path) + } else { + write!(f, "{{ {} -> INVALID }}", self.0) + } + } +} + +impl super::SysArg for FileDescriptor { + fn from_usize(value: usize) -> Self { + Self(value) + } +} + +impl From for usize { + fn from(val: FileDescriptor) -> Self { + val.0 + } +} +#[syscall] +pub fn write(fd: FileDescriptor, buffer: &[u8]) -> Result { // FIXME(heck for xeyes): fnctl should update the open flags! // // if handle // .flags // .intersects(OpenFlags::O_WRONLY | OpenFlags::O_RDWR) // { - Ok(handle.write(buffer)?) + Ok(fd.handle()?.write(buffer)?) // } else { // Err(SyscallError::EACCES) // } } #[syscall] -pub fn read(fd: usize, buffer: &mut [u8]) -> Result { - let handle = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; - - if handle - .flags - .intersects(OpenFlags::O_RDONLY | OpenFlags::O_RDWR) - { - Ok(handle.read(buffer)?) - } else { - Err(SyscallError::EACCES) - } +pub fn read(fd: FileDescriptor, buffer: &mut [u8]) -> Result { + // if handle + // .flags + // .read() + // .intersects(OpenFlags::O_RDONLY | OpenFlags::O_RDWR) + // { + Ok(fd.handle()?.read(buffer)?) + // } else { + // Err(SyscallError::EACCES) + // } } #[syscall] -pub fn open(_fd: usize, path: &Path, mode: usize) -> Result { - let mut flags = OpenFlags::from_bits(mode).ok_or(SyscallError::EINVAL)?; +pub fn open(fd: usize, path: &Path, flags: usize, _mode: usize) -> Result { + let current_thread = scheduler::current_thread(); + let at = match fd as isize { + AT_FDCWD if !path.is_absolute() => current_thread.cwd_dirent(), + _ if !path.is_absolute() => { + let ent = FileDescriptor::from_usize(fd).handle()?.inode.clone(); + assert!(ent.inode().metadata()?.is_directory()); + ent + } + _ => fs::root_dir().clone(), + }; + + let mut flags = OpenFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; if !flags.intersects(OpenFlags::O_RDONLY | OpenFlags::O_RDWR | OpenFlags::O_WRONLY) { flags.insert(OpenFlags::O_RDONLY); @@ -83,7 +125,7 @@ pub fn open(_fd: usize, path: &Path, mode: usize) -> Result lookup_mode = LookupMode::Create; } - let inode = fs::lookup_path_with_mode(path, lookup_mode)?; + let inode = fs::lookup_path_with(at, path, lookup_mode, true)?; if flags.contains(OpenFlags::O_DIRECTORY) && !inode.inode().metadata()?.is_directory() { return Err(SyscallError::ENOTDIR); @@ -93,49 +135,38 @@ pub fn open(_fd: usize, path: &Path, mode: usize) -> Result inode.inode().truncate(0)?; } - Ok(scheduler::get_scheduler() - .current_task() - .file_table - .open_file(inode, flags)?) + Ok(current_thread.file_table.open_file(inode.clone(), flags)?) } #[syscall] -pub fn dup(fd: usize, flags: usize) -> Result { +pub fn dup(fd: FileDescriptor, flags: usize) -> Result { let task = scheduler::get_scheduler().current_task(); let flags = OpenFlags::from_bits(flags).ok_or(SyscallError::EINVAL)? & OpenFlags::O_CLOEXEC; - task.file_table.duplicate(fd, DuplicateHint::Any, flags) + task.file_table + .duplicate(fd.into(), DuplicateHint::Any, flags) } #[syscall] -pub fn dup2(fd: usize, new_fd: usize, flags: usize) -> Result { +pub fn dup2(fd: FileDescriptor, new_fd: usize, flags: usize) -> Result { let task = scheduler::get_scheduler().current_task(); let flags = OpenFlags::from_bits(flags).ok_or(SyscallError::EINVAL)? & OpenFlags::O_CLOEXEC; task.file_table - .duplicate(fd, DuplicateHint::Exact(new_fd), flags) + .duplicate(fd.into(), DuplicateHint::Exact(new_fd), flags) } #[syscall] -pub fn getdents(fd: usize, buffer: &mut [u8]) -> Result { - let handle = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; - - Ok(handle.get_dents(buffer)?) +pub fn getdents(fd: FileDescriptor, buffer: &mut [u8]) -> Result { + Ok(fd.handle()?.get_dents(buffer)?) } #[syscall] -pub fn close(fd: usize) -> Result { - let res = scheduler::get_scheduler() - .current_task() - .file_table - .close_file(fd); +pub fn close(fd: FileDescriptor) -> Result { + let res = scheduler::current_thread().file_table.close_file(fd.into()); if res { - Ok(0x00) + Ok(0) } else { // FD isn't a valid open file descriptor. Err(SyscallError::EBADFD) @@ -143,16 +174,30 @@ pub fn close(fd: usize) -> Result { } #[syscall] -pub fn chdir(path: &str) -> Result { - let inode = fs::lookup_path(Path::new(path))?; +pub fn chdir(fd: usize, path: &Path) -> Result { + let current_thread = scheduler::current_thread(); + let at = match fd as isize { + AT_FDCWD if !path.is_absolute() => current_thread.cwd_dirent(), + _ if !path.is_absolute() => { + let ent = FileDescriptor::from_usize(fd).handle()?.inode.clone(); + assert!(ent.inode().metadata()?.is_directory()); + ent + } + _ => fs::root_dir().clone(), + }; - if !inode.inode().metadata()?.is_directory() { - // A component of path is not a directory. + if path.is_empty() { + current_thread.set_cwd(at); + return Ok(0); + } + + let ent = fs::lookup_path_with(at, path, LookupMode::None, true)?; + if !ent.inode().metadata()?.is_directory() { return Err(SyscallError::ENOTDIR); } - scheduler::get_scheduler().current_task().set_cwd(inode); - Ok(0x00) + current_thread.set_cwd(ent); + Ok(0) } #[syscall] @@ -169,11 +214,10 @@ pub fn mkdirat(dfd: usize, path: &Path) -> Result { // pathname is interpreted relative to the current working directory of the // calling task. if dfd as isize == aero_syscall::AT_FDCWD { - let cwd = scheduler::get_scheduler().current_task().get_cwd_dirent(); + let cwd = scheduler::current_thread().cwd_dirent(); (cwd.inode(), path.as_str()) } else { - let handle = scheduler::get_scheduler() - .current_task() + let handle = scheduler::current_thread() .file_table .get_handle(dfd) .ok_or(SyscallError::EBADFD)?; @@ -197,9 +241,7 @@ pub fn mkdirat(dfd: usize, path: &Path) -> Result { } #[syscall] -pub fn rmdir(path: &str) -> Result { - let path = Path::new(path); - +pub fn rmdir(path: &Path) -> Result { let (_, child) = path.parent_and_basename(); let inode = fs::lookup_path(path)?; @@ -216,26 +258,34 @@ pub fn rmdir(path: &str) -> Result { #[syscall] pub fn getcwd(buffer: &mut [u8]) -> Result { - let cwd = scheduler::get_scheduler().current_task().get_cwd(); + let cwd = scheduler::current_thread().get_cwd(); + log::debug!("getcwd: {}", cwd); + // FIXME: fix this before commiting + buffer.fill(0); buffer[..cwd.len()].copy_from_slice(cwd.as_bytes()); + + // TOOD: mlibc doesnt give a shit and will increase the buf size till it fits. make it smarter. Ok(cwd.len()) } #[syscall] -pub fn ioctl(fd: usize, command: usize, argument: usize) -> Result { - let handle = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; +pub fn ioctl(fd: FileDescriptor, command: usize, argument: usize) -> Result { + let handle = fd.handle()?; match command { // Sets the close-on-exec file descriptor flag. This is equivalent // to `fcntl(fd, F_SETFD, FD_CLOEXEC)` FIOCLEX => { - handle.fd_flags.lock().insert(FdFlags::CLOEXEC); - return Ok(0x00); + let flags = handle.flags(); + handle.set_flags(flags | OpenFlags::O_CLOEXEC); + Ok(0) + } + + FIONBIO => { + let flags = handle.flags(); + handle.set_flags(flags | OpenFlags::O_NONBLOCK); + Ok(0) } // Handle file specific ioctl: @@ -244,13 +294,8 @@ pub fn ioctl(fd: usize, command: usize, argument: usize) -> Result Result { - let handle = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; - +pub fn seek(fd: FileDescriptor, offset: usize, whence: usize) -> Result { + let handle = fd.handle()?; Ok(handle.seek(offset as isize, aero_syscall::SeekWhence::from(whence))?) } @@ -261,8 +306,8 @@ pub fn pipe(fds: &mut [i32; 2], flags: usize) -> Result { let entry = DirEntry::from_inode(pipe, String::from("")); - let flags_1 = OpenFlags::O_RDONLY | (flags & OpenFlags::O_CLOEXEC); - let flags_2 = OpenFlags::O_WRONLY | (flags & OpenFlags::O_CLOEXEC); + let flags_1 = OpenFlags::O_RDONLY | flags; + let flags_2 = OpenFlags::O_WRONLY | flags; let current_task = scheduler::get_scheduler().current_task(); @@ -287,47 +332,55 @@ pub fn pipe(fds: &mut [i32; 2], flags: usize) -> Result { } #[syscall] -pub fn unlink(fd: usize, path: &Path, flags: usize) -> Result { - // TODO: Make use of the open flags. - let _flags = OpenFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; - let name = path.container(); +pub fn unlink(_fd: usize, _path: &Path, _flags: usize) -> Result { + // let _flags = OpenFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; + // let name = path.container(); - if fd as isize == aero_syscall::AT_FDCWD { - let file = fs::lookup_path(path)?; + // if fd as isize == aero_syscall::AT_FDCWD { + // let file = fs::lookup_path(path)?; - if let Some(dir) = file.parent() { - let metadata = file.inode().metadata()?; + // if let Some(dir) = file.parent() { + // let metadata = file.inode().metadata()?; - if metadata.is_file() { - dir.inode().unlink(name.as_str())?; - file.drop_from_cache(); - } - } - } else { - unimplemented!() - } + // if metadata.is_file() { + // dir.inode().unlink(name.as_str())?; + // file.drop_from_cache(); + // } + // } + // } else { + // unimplemented!() + // } Ok(0x00) } #[syscall] -pub fn access(fd: usize, path: &Path, _mode: usize, _flags: usize) -> Result { - if fd as isize == aero_syscall::AT_FDCWD { - lookup_path(path)?; - Ok(0x00) - } else { - // TODO: Implement atfd access - unimplemented!() - } +pub fn access(fd: usize, path: &Path, _mode: usize, flags: usize) -> Result { + let at = match fd as isize { + AT_FDCWD if !path.is_absolute() => scheduler::current_thread().cwd_dirent(), + _ if !path.is_absolute() => FileDescriptor::from_usize(fd).handle()?.inode.clone(), + _ => fs::root_dir().clone(), + }; + + let flags = AtFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; + + let resolve_last = !flags.contains(AtFlags::SYMLINK_NOFOLLOW); + let _ = fs::lookup_path_with(at, path, LookupMode::None, resolve_last)?; + + Ok(0) } +const SETFL_MASK: OpenFlags = OpenFlags::from_bits_truncate( + OpenFlags::O_APPEND.bits() + | OpenFlags::O_NONBLOCK.bits() + // | OpenFlags::O_NDELAY.bits() + | OpenFlags::O_DIRECT.bits() + | OpenFlags::O_NOATIME.bits(), +); + #[syscall] -pub fn fcntl(fd: usize, command: usize, arg: usize) -> Result { - let handle = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; +pub fn fcntl(fd: FileDescriptor, command: usize, arg: usize) -> Result { + let handle = fd.handle()?; match command { // F_DUPFD_CLOEXEC and F_DUPFD: @@ -339,68 +392,129 @@ pub fn fcntl(fd: usize, command: usize, arg: usize) -> Result scheduler::get_scheduler() - .current_task() - .file_table - .duplicate(fd, DuplicateHint::GreatorOrEqual(arg), OpenFlags::O_CLOEXEC), + aero_syscall::prelude::F_DUPFD => scheduler::current_thread().file_table.duplicate( + fd.into(), + DuplicateHint::GreatorOrEqual(arg), + handle.flags(), + ), + + aero_syscall::prelude::F_DUPFD_CLOEXEC => scheduler::current_thread().file_table.duplicate( + fd.into(), + DuplicateHint::GreatorOrEqual(arg), + handle.flags() | OpenFlags::O_CLOEXEC, + ), // Get the value of file descriptor flags. aero_syscall::prelude::F_GETFD => { - let flags = handle.fd_flags.lock().bits(); - Ok(flags) + let flags = handle.flags(); + let mut result = FdFlags::empty(); + + if flags.contains(OpenFlags::O_CLOEXEC) { + result.insert(FdFlags::CLOEXEC); + } + + Ok(result.bits()) } // Set the value of file descriptor flags: aero_syscall::prelude::F_SETFD => { - let flags = FdFlags::from_bits(arg).ok_or(SyscallError::EINVAL)?; - handle.fd_flags.lock().insert(flags); + let mut flags = handle.flags(); + let fd_flags = FdFlags::from_bits_truncate(arg); + + if fd_flags.contains(FdFlags::CLOEXEC) { + flags.insert(OpenFlags::O_CLOEXEC); + } else { + flags.remove(OpenFlags::O_CLOEXEC); + } - Ok(0x00) + handle.set_flags(flags); + Ok(0) } // Get the value of file status flags: - aero_syscall::prelude::F_GETFL => { - let flags = handle.flags.bits(); - Ok(flags) - } + aero_syscall::prelude::F_GETFL => Ok(handle.flags().bits()), aero_syscall::prelude::F_SETFL => { - log::debug!("F_SETFL: is a stub!"); + let flags = OpenFlags::from_bits_truncate(arg); + let old_flags = handle.flags(); + handle.set_flags((flags & SETFL_MASK) | (old_flags & !SETFL_MASK)); - Ok(0x00) + Ok(0) } - _ => unimplemented!("fcntl: unknown command {command}"), + aero_syscall::prelude::F_SETLKW | aero_syscall::prelude::F_SETLK => { + log::warn!("fcntl: F_SETLKW,F_SETLK are a stub!"); + Ok(0) + } + + _ => { + log::error!("fcntl: unknown command {command}"); + Ok(0) + } } } #[syscall] -pub fn fstat(fd: usize, stat: &mut Stat) -> Result { - let file = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(fd) - .ok_or(SyscallError::EBADFD)?; +pub fn fstat(fd: usize, path: &Path, flags: usize, stat: &mut Stat) -> Result { + let at = match fd as isize { + AT_FDCWD if !path.is_absolute() => scheduler::current_thread().cwd_dirent(), + _ if !path.is_absolute() => FileDescriptor::from_usize(fd).handle()?.inode.clone(), + _ => fs::root_dir().clone(), + }; - *stat = file.inode().stat()?; + // TODO: derive(SysArg) for bitflags. + let flags = AtFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; + assert!(!flags.intersects(AtFlags::EACCESS | AtFlags::REMOVEDIR)); + + if path.is_empty() { + if !flags.contains(AtFlags::EMPTY_PATH) { + return Err(SyscallError::EINVAL); + } + + *stat = at.inode().stat()?; + return Ok(0); + } + let resolve_last = !flags.contains(AtFlags::SYMLINK_NOFOLLOW); + let ent = fs::lookup_path_with(at, path, LookupMode::None, resolve_last)?; + *stat = ent.inode().stat()?; Ok(0) } #[syscall] pub fn stat(path: &Path, stat: &mut Stat) -> Result { let file = fs::lookup_path(path)?; - *stat = file.inode().stat()?; - Ok(0) } #[syscall] -pub fn read_link(path: &Path, _buffer: &mut [u8]) -> Result { - log::warn!("read_link: is a stub! (path={path:?})"); +pub fn read_link(path: &Path, buffer: &mut [u8]) -> Result { + // XXX: lookup_path with automatically resolve the link. + let cwd = if !path.is_absolute() { + scheduler::current_thread().cwd_dirent() + } else { + fs::root_dir().clone() + }; - Err(SyscallError::EINVAL) + let file = fs::lookup_path_with(cwd.clone(), path, LookupMode::None, false)?.inode(); + if !file.metadata()?.is_symlink() { + return Err(SyscallError::EINVAL); + } + + let resolved_path = file.resolve_link()?; + let resolved_path = if resolved_path.is_absolute() { + resolved_path + } else { + cwd.absolute_path().join(resolved_path) + }; + + let size = core::cmp::min(resolved_path.as_str().len(), buffer.len()); + + log::warn!("Orig: {path:?} -> {resolved_path}"); + + buffer[..size].copy_from_slice(&resolved_path.as_bytes()[..size]); + Ok(size) } /// Returns a file descriptor referring to the new epoll instance. @@ -422,16 +536,12 @@ pub fn epoll_create(flags: usize) -> Result { /// the operation be performed for the target file descriptor. #[syscall] pub fn epoll_ctl( - epfd: usize, + epfd: FileDescriptor, mode: usize, fd: usize, event: &mut EPollEvent, ) -> Result { - let epfd = scheduler::get_scheduler() - .current_task() - .file_table - .get_handle(epfd) - .ok_or(SyscallError::EBADFD)?; + let epfd = epfd.handle()?; let epoll = epfd .inode() @@ -440,7 +550,7 @@ pub fn epoll_ctl( match mode { EPOLL_CTL_ADD => { - epoll.add_event(fd, event.clone())?; + epoll.add_event(fd, *event)?; Ok(0) } @@ -450,7 +560,7 @@ pub fn epoll_ctl( } EPOLL_CTL_MOD => { - epoll.update_event(fd, event.clone())?; + epoll.update_event(fd, *event)?; Ok(0) } @@ -460,8 +570,8 @@ pub fn epoll_ctl( #[syscall] pub fn epoll_pwait( - epfd: usize, - event: &mut [&mut EPollEvent], + epfd: FileDescriptor, + event: &mut [EPollEvent], timeout: usize, sigmask: usize, ) -> Result { @@ -470,11 +580,7 @@ pub fn epoll_pwait( let current_task = scheduler::get_scheduler().current_task(); let signals = current_task.signals(); - let epfd = current_task - .file_table - .get_handle(epfd) - .ok_or(SyscallError::EBADFD)?; - + let epfd = epfd.handle()?; let epfd = epfd .inode() .downcast_arc::() @@ -487,7 +593,7 @@ pub fn epoll_pwait( let result = epfd.wait(event, max_events, timeout)?; - // Restore the orignal signal mask. + // Restore the original signal mask. signals.set_mask(SigProcMask::Set, Some(old_mask), None); Ok(result) } @@ -511,18 +617,21 @@ pub fn event_fd(_initval: usize, flags: usize) -> Result { /// file. #[syscall] pub fn link(src_path: &Path, dest_path: &Path) -> Result { - let src = fs::lookup_path(src_path)?.inode(); + let src = fs::lookup_path(src_path)?; let (dest_dir, dest_name) = dest_path.parent_and_basename(); let dest_dir = fs::lookup_path(dest_dir)?.inode(); // Cannot create a hardlink to a file on a different filesystem. // - // SAFTEY: The pointers to the file system are valid since we know that there are + // SAFETY: The pointers to the file system are valid since we know that there are // strong references to it. // // TODO: Should this be moved to the inode impl? - if dest_dir.weak_filesystem().unwrap().as_ptr() != src.weak_filesystem().unwrap().as_ptr() { + if !Weak::ptr_eq( + &dest_dir.weak_filesystem().unwrap(), + &src.inode().weak_filesystem().unwrap(), + ) { return Err(SyscallError::EINVAL); } @@ -539,16 +648,17 @@ fn do_poll(fds: &mut [PollFd], timeout: Option<&TimeSpec>) -> Result v, None => { - fd.revents = PollEventFlags::empty(); return Ok(0); } }; @@ -570,7 +680,6 @@ fn do_poll(fds: &mut [PollFd], timeout: Option<&TimeSpec>) -> Result 0 { - debug_assert!(refds.len() == 0); return Ok(n); } @@ -582,11 +691,8 @@ fn do_poll(fds: &mut [PollFd], timeout: Option<&TimeSpec>) -> Result) -> Result Result { // Nothing to poll on. - if fds.len() == 0 { + if fds.is_empty() { return Ok(0); } // The timeout can be NULL. let timeout = if timeout != 0x00 { - Some(crate::utils::validate_ptr(timeout as *const TimeSpec).ok_or(SyscallError::EINVAL)?) + Some(crate::utils::validate_ptr(timeout as *const TimeSpec)?) } else { None }; @@ -624,7 +730,47 @@ pub fn poll(fds: &mut [PollFd], timeout: usize, sigmask: usize) -> Result Result { + let src = fs::lookup_path(src)?; + let (dest, name) = { + let (dir, name) = dest.parent_and_basename(); + (fs::lookup_path(dir)?, name) + }; + + dest.inode().rename(src.clone(), name)?; + + cache::dcache().rehash(src.clone(), || { + src.set_name(name); + src.set_parent(dest); + }); + Ok(0) +} + +#[syscall] +pub fn symlink(link_dirfd: usize, target: &Path, linkpath: &Path) -> Result { + // TODO(andypython): the following code is reused in a couple of places. Isolate this inside the + // syscall parsing for FileDescriptor with an argument as a generic specifing the allowance + // of this value. + // + // If the pathname given in `linkpath` is relative, then it is interpreted relative to the + // directory referred to by the file descriptor `link_dirfd`. + let at = match link_dirfd as isize { + AT_FDCWD if !linkpath.is_absolute() => scheduler::current_thread().cwd_dirent(), + _ if !linkpath.is_absolute() => FileDescriptor::from_usize(link_dirfd) + .handle()? + .inode + .clone(), + _ => fs::root_dir().clone(), + }; + + let ent = fs::lookup_path_with(at, linkpath, LookupMode::Create, false)?; + ent.inode().symlink(target)?; + + Ok(0) +} diff --git a/src/aero_kernel/src/syscall/futex.rs b/src/aero_kernel/src/syscall/futex.rs index e1e4280d848..82ff559b448 100644 --- a/src/aero_kernel/src/syscall/futex.rs +++ b/src/aero_kernel/src/syscall/futex.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::sync::atomic::{AtomicU32, Ordering}; @@ -26,10 +24,10 @@ use spin::Once; use crate::mem::paging::{PhysAddr, Translate, VirtAddr}; use crate::mem::AddressSpace; use crate::userland::scheduler; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::utils::sync::{Mutex, WaitQueue}; pub struct FutexContainer { - futexes: Mutex>>, + futexes: Mutex>>, } impl FutexContainer { @@ -60,21 +58,21 @@ impl FutexContainer { } /// Returns the futex at the given key; allocating it if it doesn't exist. - fn get_alloc(&self, key: PhysAddr) -> Arc { + fn get_alloc(&self, key: PhysAddr) -> Arc { let mut container = self.futexes.lock(); if let Some(futex) = container.get(&key) { futex.clone() } else { - let futex = Arc::new(BlockQueue::new()); + let futex = Arc::new(WaitQueue::new()); container.insert(key, futex.clone()); futex } } /// Returns the futex at the given key, or None if it doesn't exist. - fn get(&self, key: PhysAddr) -> Option> { - self.futexes.lock_irq().get(&key).map(|e| e.clone()) + fn get(&self, key: PhysAddr) -> Option> { + self.futexes.lock_irq().get(&key).cloned() } /// Tests the that the value at the futex word pointed to by `uaddr` still contains the @@ -89,7 +87,7 @@ impl FutexContainer { Self::validate_futex_ptr(uaddr)?; let key = Self::addr_as_futex_key(uaddr).ok_or(SyscallError::EINVAL)?; - let value = uaddr.read_mut::().ok_or(SyscallError::EINVAL)?; + let value = uaddr.read_mut::()?; if value.load(Ordering::SeqCst) == expected { let futex = self.get_alloc(key); @@ -98,8 +96,8 @@ impl FutexContainer { let current_task = scheduler.current_task(); futex.insert(current_task.clone()); - scheduler.inner.await_io()?; - futex.remove(current_task); + scheduler.await_io()?; + futex.remove(¤t_task); if futex.is_empty() { self.futexes.lock().remove(&key); @@ -117,7 +115,7 @@ impl FutexContainer { let key = Self::addr_as_futex_key(uaddr).ok_or(SyscallError::EINVAL)?; let futex = self.get(key).ok_or(SyscallError::EINVAL)?; - futex.notify_complete(); + futex.notify_all(); // todo: early reschedule if the futex is not empty. Ok(()) @@ -126,16 +124,16 @@ impl FutexContainer { static FUTEX_CONTAINER: Once = Once::new(); -/// Returns a reference to the futex conatiner; initializing if necessary. -fn get_futex_conatiner() -> &'static FutexContainer { - FUTEX_CONTAINER.call_once(|| FutexContainer::new()) +/// Returns a reference to the futex container; initializing if necessary. +fn get_futex_container() -> &'static FutexContainer { + FUTEX_CONTAINER.call_once(FutexContainer::new) } #[syscall] pub fn wait(ptr: usize, expected: usize, timeout: &TimeSpec) -> Result { let ptr = VirtAddr::new(ptr as u64); - let futex_container = get_futex_conatiner(); + let futex_container = get_futex_container(); futex_container.wait(ptr, expected as u32, timeout)?; Ok(0) @@ -145,7 +143,7 @@ pub fn wait(ptr: usize, expected: usize, timeout: &TimeSpec) -> Result Result { let ptr = VirtAddr::new(ptr as u64); - let futex_container = get_futex_conatiner(); + let futex_container = get_futex_container(); futex_container.wake(ptr)?; Ok(0) diff --git a/src/aero_kernel/src/syscall/ipc.rs b/src/aero_kernel/src/syscall/ipc.rs index 21afd898bf1..d1bede83519 100644 --- a/src/aero_kernel/src/syscall/ipc.rs +++ b/src/aero_kernel/src/syscall/ipc.rs @@ -1,29 +1,28 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use crate::userland::scheduler::get_scheduler; use crate::userland::task::TaskId; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueFlags}; use aero_syscall::SyscallError; -use alloc::{collections::VecDeque, vec::Vec}; +use alloc::collections::VecDeque; +use alloc::vec::Vec; use spin::Once; // TODO: Make this reassignable in case we want to handle the root node's death, so @@ -37,19 +36,19 @@ struct Message { pub struct MessageQueue { queue: Mutex>, - blockqueue: BlockQueue, + blockqueue: WaitQueue, } impl MessageQueue { pub fn new() -> MessageQueue { MessageQueue { queue: Mutex::new(VecDeque::new()), - blockqueue: BlockQueue::new(), + blockqueue: WaitQueue::new(), } } } -fn handle_recieve( +fn handle_receive( pid_ptr: &mut usize, output: &mut [u8], msg: Message, @@ -77,7 +76,7 @@ pub fn send(pid: usize, payload: &[u8]) -> Result { }); // Notify the task that it has a new message if its awaiting for one! - message_queue.blockqueue.notify_complete(); + message_queue.blockqueue.notify_all(); Ok(0) } @@ -98,24 +97,26 @@ pub fn recv(pid_ptr: &mut usize, output: &mut [u8], block: usize) -> Result output.len() { our_queue.push_front(msg); Err(SyscallError::E2BIG) } else { - handle_recieve(pid_ptr, output, msg) + handle_receive(pid_ptr, output, msg) } } diff --git a/src/aero_kernel/src/syscall/mod.rs b/src/aero_kernel/src/syscall/mod.rs index a38a4bbfbcc..492a6da5998 100644 --- a/src/aero_kernel/src/syscall/mod.rs +++ b/src/aero_kernel/src/syscall/mod.rs @@ -1,98 +1,37 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . //! System Calls are used to call a kernel service from userland. -//! -//! | %rax | Name | -//! |--------|-------------------------| -//! | 0 | read | -//! | 1 | write | -//! | 2 | open | -//! | 3 | close | -//! | 4 | shutdown | -//! | 5 | exit | -//! | 6 | fork | -//! | 7 | reboot | -//! | 8 | mmap | -//! | 9 | munmap | -//! | 10 | arch_prctl | -//! | 11 | get_dents | -//! | 12 | get_cwd | -//! | 13 | chdir | -//! | 14 | mkdir | -//! | 15 | mkdirat | -//! | 16 | rmdir | -//! | 17 | exec | -//! | 18 | log | -//! | 19 | uname | -//! | 20 | waitpid | -//! | 21 | ioctl | -//! | 22 | getpid | -//! | 23 | socket | -//! | 24 | connect | -//! | 25 | bind | -//! | 26 | listen | -//! | 27 | accept | -//! | 28 | seek | -//! | 29 | gettid | -//! | 30 | gettime | -//! | 31 | sleep | -//! | 32 | access | -//! | 33 | pipe | -//! | 34 | unlink | -//! | 35 | gethostname | -//! | 36 | sethostname | -//! | 37 | info | -//! | 38 | clone | -//! | 39 | sigreturn | -//! | 40 | sigaction | -//! | 41 | sigprocmask | -//! | 42 | dup | -//! | 43 | fcntl | -//! | 44 | dup2 | -//! | 45 | ipc_send | -//! | 46 | ipc_recv | -//! | 47 | ipc_discover_root | -//! | 48 | ipc_become_root | -//! | 49 | stat | -//! | 50 | fstat | -//! | 51 | read_link | +use core::fmt::Display; use core::mem::MaybeUninit; use aero_syscall::prelude::*; mod fs; mod futex; -mod ipc; +pub mod ipc; mod net; mod process; -mod time; +pub mod time; use alloc::boxed::Box; use alloc::vec::Vec; -pub use fs::*; -pub use ipc::*; -pub use process::*; -pub use time::*; - use crate::utils::StackHelper; #[derive(Default)] @@ -155,7 +94,16 @@ pub fn exec_args_from_slice(args: usize, size: usize) -> ExecArgs { ExecArgs { inner: result } } -#[cfg(feature = "syslog")] +pub trait SysArg: Display { + fn from_usize(value: usize) -> Self; +} + +impl SysArg for usize { + fn from_usize(value: usize) -> Self { + value + } +} + pub(super) struct SysLog { name: &'static str, /// The result of the syscall. @@ -164,7 +112,6 @@ pub(super) struct SysLog { args: Vec, } -#[cfg(feature = "syslog")] impl SysLog { pub fn new(name: &'static str) -> Self { Self { @@ -198,7 +145,7 @@ impl SysLog { pub fn flush(self) { let mut result = String::new(); - if self.result.map(|e| e.is_ok()).unwrap_or_default() { + if self.result.unwrap().is_ok() { result.push_str("\x1b[1;32m"); } else { result.push_str("\x1b[1;31m"); @@ -216,6 +163,10 @@ impl SysLog { result.push_str(alloc::format!(") = {:?}", self.result.unwrap()).as_str()); log::trace!("{result}"); + + if self.result.unwrap().is_err() { + crate::unwind::unwind_stack_trace(); + } } } @@ -234,11 +185,13 @@ pub fn generic_do_syscall( SYS_FORK => process::fork(), SYS_MMAP => process::mmap(b, c, d, e, f, g), SYS_MUNMAP => process::munmap(b, c), + SYS_MPROTECT => process::mprotect(b, c, d), SYS_EXEC => process::exec(b, c, d, e, f, g), SYS_LOG => process::log(b, c), SYS_UNAME => process::uname(b), SYS_WAITPID => process::waitpid(b, c, d), SYS_GETPID => process::getpid(), + SYS_GETPPID => process::getppid(), SYS_GETTID => process::gettid(), SYS_GETHOSTNAME => process::gethostname(b, c), SYS_SETHOSTNAME => process::sethostname(b, c), @@ -248,14 +201,18 @@ pub fn generic_do_syscall( SYS_CLONE => process::clone(b, c), SYS_KILL => process::kill(b, c), SYS_BACKTRACE => process::backtrace(), + SYS_TRACE => process::trace(), + SYS_SETPGID => process::setpgid(b, c), + SYS_SETSID => process::setsid(), + SYS_GETPGID => process::getpgid(b), SYS_READ => fs::read(b, c, d), - SYS_OPEN => fs::open(b, c, d, e), + SYS_OPEN => fs::open(b, c, d, e, f), SYS_CLOSE => fs::close(b), SYS_WRITE => fs::write(b, c, d), SYS_GETDENTS => fs::getdents(b, c, d), SYS_GETCWD => fs::getcwd(b, c), - SYS_CHDIR => fs::chdir(b, c), + SYS_CHDIR => fs::chdir(b, c, d), SYS_MKDIR_AT => fs::mkdirat(b, c, d), SYS_RMDIR => fs::rmdir(b, c), SYS_IOCTL => fs::ioctl(b, c, d), @@ -267,11 +224,13 @@ pub fn generic_do_syscall( SYS_DUP2 => fs::dup2(b, c, d), SYS_FCNTL => fs::fcntl(b, c, d), SYS_STAT => fs::stat(b, c, d), - SYS_FSTAT => fs::fstat(b, c), + SYS_FSTAT => fs::fstat(b, c, d, e, f), SYS_READ_LINK => fs::read_link(b, c, d, e), SYS_EVENT_FD => fs::event_fd(b, c), SYS_LINK => fs::link(b, c, d, e), SYS_POLL => fs::poll(b, c, d, e), + SYS_RENAME => fs::rename(b, c, d, e), + SYS_SYMLINK_AT => fs::symlink(b, c, d, e, f), // epoll calls: SYS_EPOLL_CREATE => fs::epoll_create(b), @@ -284,6 +243,12 @@ pub fn generic_do_syscall( SYS_LISTEN => net::listen(b, c), SYS_ACCEPT => net::accept(b, c, d), SYS_SOCK_RECV => net::sock_recv(b, c, d), + SYS_SOCK_SEND => net::sock_send(b, c, d), + SYS_SOCKET_PAIR => net::socket_pair(b, c, d, e), + SYS_SOCK_SHUTDOWN => net::shutdown(b, c), + SYS_GETPEERNAME => net::get_peername(b, c, d), + SYS_GETSOCKNAME => net::get_sockname(b, c, d), + SYS_SETSOCKOPT => net::setopt(a, b, c, d, e), SYS_GETTIME => time::gettime(b, c), SYS_SLEEP => time::sleep(b), @@ -302,6 +267,8 @@ pub fn generic_do_syscall( // Syscall aliases (this should be handled in aero_syscall) SYS_MKDIR => fs::mkdirat(aero_syscall::AT_FDCWD as _, b, c), + SYS_DEBUG => tag_memory(b, c, d, e), + _ => { log::error!("invalid syscall: {:#x}", a); Err(SyscallError::ENOSYS) @@ -310,3 +277,19 @@ pub fn generic_do_syscall( aero_syscall::syscall_result_as_usize(result) } + +#[syscall] +pub fn tag_memory(ptr: *const u8, size: usize, tag: &str) -> Result { + use crate::userland::scheduler; + use alloc::string::ToString; + + let addr = ptr as usize; + + let thread = scheduler::current_thread(); + thread + .mem_tags + .lock() + .insert(addr..(addr + size), tag.to_string()); + + Ok(0) +} diff --git a/src/aero_kernel/src/syscall/net.rs b/src/aero_kernel/src/syscall/net.rs index 7c713d05711..9f36d796db5 100644 --- a/src/aero_kernel/src/syscall/net.rs +++ b/src/aero_kernel/src/syscall/net.rs @@ -1,29 +1,62 @@ -use aero_syscall::socket::MessageHeader; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::netlink::sockaddr_nl; +use aero_syscall::socket::{MessageFlags, MessageHeader, SocketOptionLevel}; use aero_syscall::*; +use alloc::sync::Arc; +use num_traits::cast::FromPrimitive; + +use crate::arch::user_copy::UserRef; -use crate::fs::inode::DirEntry; +use crate::fs::cache::DirCacheItem; +use crate::fs::inode::{DirEntry, INodeInterface}; use crate::mem::paging::VirtAddr; +use crate::socket::ipv4::Ipv4Socket; +use crate::socket::netlink::NetLinkSocket; +use crate::socket::tcp::TcpSocket; +use crate::socket::udp::UdpSocket; use crate::socket::unix::*; -use crate::socket::SocketAddr; +use crate::socket::{SocketAddr, SocketAddrRef}; use crate::userland::scheduler; -use crate::utils; + +use crate::syscall::fs::FileDescriptor; /// Creates a [`SocketAddr`] from the provided userland socket structure address. This /// is done by looking at the family field present in every socket address structure. -fn socket_addr_from_addr<'sys>(address: VirtAddr) -> Result, SyscallError> { - let family = address - .read_mut::() - .ok_or(SyscallError::EINVAL)? - .clone(); +fn socket_addr_from_addr<'sys>(address: VirtAddr) -> Result> { + let family = *address.read_mut::()?; + SocketAddrRef::from_family(address, family) +} + +#[syscall] +pub fn shutdown(fd: usize, how: usize) -> Result { + let file_table = &scheduler::get_scheduler().current_task().file_table; + let socket = file_table.get_handle(fd).ok_or(SyscallError::EINVAL)?; - Ok(SocketAddr::from_family(address, family).ok_or(SyscallError::EINVAL)?) + socket.inode().shutdown(how)?; + Ok(0) } /// Connects the socket to the specified address. #[syscall] -pub fn connect(fd: usize, address: usize, length: usize) -> Result { +pub fn connect(fd: usize, address: usize, length: usize) -> Result { let address = socket_addr_from_addr(VirtAddr::new(address as u64))?; let file = scheduler::get_scheduler() .current_task() @@ -37,21 +70,19 @@ pub fn connect(fd: usize, address: usize, length: usize) -> Result Result { - // TODO: In the syscall macro, handle Option> param. - let address = if address != 0 { - Some(utils::validate_mut_ptr(address as *mut SocketAddr).ok_or(SyscallError::EINVAL)?) +pub fn accept(fd: usize, address: usize, length: usize) -> Result { + let file_table = scheduler::get_scheduler().current_task().file_table.clone(); + let socket = file_table.get_handle(fd).ok_or(SyscallError::EINVAL)?; + + let address = if address != 0 && length != 0 { + Some(( + VirtAddr::new(address as u64), + VirtAddr::new(length as u64).read_mut::()?, + )) } else { None }; - let file_table = scheduler::get_scheduler().current_task().file_table.clone(); - let socket = file_table.get_handle(fd).ok_or(SyscallError::EINVAL)?; - let connection_sock = socket.inode().accept(address)?; let handle = file_table.open_file( DirEntry::from_inode(connection_sock, String::from("")), @@ -62,60 +93,126 @@ pub fn accept( } #[syscall] -pub fn sock_recv( - sockfd: usize, - header: &mut MessageHeader, - flags: usize, -) -> Result { - assert!(flags == 0, "sock_recv: flags are not currently supported"); +pub fn sock_send(fd: usize, header: &mut MessageHeader, flags: usize) -> Result { + dbg!(header.control()); + + let flags = MessageFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; let current_task = scheduler::get_scheduler().current_task(); let socket = current_task .file_table - .get_handle(sockfd) + .get_handle(fd) .ok_or(SyscallError::EINVAL)?; - Ok(socket.inode().recv(header)?) + Ok(socket.inode().send(header, flags)?) } -/// Marks the socket as a passive socket (i.e. as a socket that will be used to accept incoming -/// connection requests). #[syscall] -pub fn listen(fd: usize, backlog: usize) -> Result { - let file = scheduler::get_scheduler() - .current_task() +pub fn sock_recv(sockfd: usize, header: &mut MessageHeader, flags: usize) -> Result { + let flags = MessageFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; + + let current_task = scheduler::get_scheduler().current_task(); + let socket = current_task .file_table - .get_handle(fd) + .get_handle(sockfd) .ok_or(SyscallError::EINVAL)?; - file.inode().listen(backlog)?; + Ok(socket.inode().recv(socket.flags(), header, flags)?) +} + +#[syscall] +pub fn setopt(fd: FileDescriptor, layer: usize, number: usize, buf: &[u8]) -> Result { + let layer = SocketOptionLevel::from_usize(layer).ok_or(SyscallError::EINVAL)?; + + match layer { + SocketOptionLevel::Socket => { + unimplemented!( + "setsockopt(fd={:?}, layer={:?}, number={:?}, buf={:?})", + fd, + layer, + number, + buf + ) + } + + _ => todo!(), + } + Ok(0) } +/// Marks the socket as a passive socket (i.e. as a socket that will be used to accept incoming +/// connection requests). #[syscall] -pub fn socket(domain: usize, socket_type: usize, protocol: usize) -> Result { - let socket = match domain as u32 { - AF_UNIX => UnixSocket::new(), +pub fn listen(fd: FileDescriptor, backlog: usize) -> Result { + fd.handle()?.inode().listen(backlog)?; + Ok(0) +} + +fn create_socket(domain: usize, socket_type: usize, protocol: usize) -> Result { + let typ = SocketType::from_usize(socket_type & 0b1111).ok_or(SyscallError::EINVAL)?; + let protocol = IpProtocol::from_usize(protocol).ok_or(SyscallError::EINVAL)?; + + let (name, socket) = match domain as u32 { + AF_UNIX => ("unix", UnixSocket::new() as Arc), + AF_INET => match (typ, protocol) { + (SocketType::Dgram, IpProtocol::Default | IpProtocol::Udp) => { + ("udp", UdpSocket::new() as Arc) + } + + (SocketType::Dgram, IpProtocol::Raw) => { + ("ipv4", Ipv4Socket::new() as Arc) + } + + (SocketType::Stream, IpProtocol::Default | IpProtocol::Tcp) => { + ("tcp", TcpSocket::new() as Arc) + } + + _ => { + log::warn!( + "unsupported socket type: domain={domain}, socket_type={socket_type}, protocol={protocol:?}" + ); + + return Err(SyscallError::EINVAL); + } + }, + + AF_NETLINK => ("netlink", NetLinkSocket::new() as Arc), + _ => { log::warn!( - "unsupported socket type: domain={domain}, socket_type={socket_type}, protocol={protocol}" + "unsupported socket type: domain={domain}, socket_type={socket_type}, protocol={protocol:?}" ); return Err(SyscallError::EINVAL); } }; + log::warn!("<{name}_socket> -EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"); - let sockfd_flags = SocketFlags::from_bits_truncate(socket_type).into(); + let entry = DirEntry::from_inode(socket, alloc::format!("<{name}_socket>")); + Ok(entry) +} + +#[syscall] +pub fn socket(domain: usize, socket_type: usize, protocol: usize) -> Result { + let entry = create_socket(domain, socket_type, protocol)?; - let entry = DirEntry::from_inode(socket, String::from("")); let current_task = scheduler::get_scheduler().current_task(); - let fd = current_task.file_table.open_file(entry, sockfd_flags)?; + + let sockfd_flags = SocketFlags::from_bits_truncate(socket_type).into(); + let fd = dbg!(current_task.file_table.debug_open_file(entry, sockfd_flags))?; + // if fd == 17 { + // scheduler::get_scheduler() + // .find_task(TaskId::new(40)) + // .unwrap() + // .enable_systrace(); + // } Ok(fd) } #[syscall] -pub fn bind(fd: usize, address: usize, length: usize) -> Result { +pub fn bind(fd: usize, address: usize, length: usize) -> Result { let address = socket_addr_from_addr(VirtAddr::new(address as u64))?; let current_task = scheduler::get_scheduler().current_task(); @@ -134,3 +231,115 @@ pub fn bind(fd: usize, address: usize, length: usize) -> Result Err(SyscallError::ENOENT), } } + +// TODO(andypython): bindgen the abi-bits from mlibc and use those types instead. +#[syscall] +pub fn get_peername(fd: usize, addr: usize, len: &mut u32) -> Result { + let thread = scheduler::current_thread(); + let file = thread + .file_table + .get_handle(fd) + .ok_or(SyscallError::ENOENT)?; + + let inode = file.inode(); + if !inode.metadata()?.is_socket() { + return Err(SyscallError::ENOTSOCK); + } + + let peer = inode.get_peername()?; + + match peer { + SocketAddr::Inet(peer) => { + let size = core::mem::size_of::() as u32; + assert!(*len >= size); + + let mut target = unsafe { UserRef::::new(VirtAddr::new(addr as u64)) }; + *target = peer; + *len = size; + } + + SocketAddr::Netlink(peer) => unimplemented!("{:?}", peer), + SocketAddr::Unix(peer) => { + let size = core::mem::size_of::() as u32; + assert!(*len >= size); + + let mut target = unsafe { &mut *(addr as *mut SocketAddrUnix) }; + *len = peer.path_len() as u32 + core::mem::offset_of!(SocketAddrUnix, path) as u32; + *target = peer; + } + } + + Ok(0) +} + +#[syscall] +pub fn get_sockname(fd: usize, addr: usize, len: &mut u32) -> Result { + let thread = scheduler::current_thread(); + let file = thread + .file_table + .get_handle(fd) + .ok_or(SyscallError::ENOENT)?; + + let inode = file.inode(); + if !inode.metadata()?.is_socket() { + return Err(SyscallError::ENOTSOCK); + } + + let name = inode.get_sockname()?; + + // CLEANME: TODO: FIXME: + match name { + SocketAddr::Inet(name) => { + let size = core::mem::size_of::() as u32; + assert!(*len >= size); + + let mut target = unsafe { UserRef::::new(VirtAddr::new(addr as u64)) }; + *target = name; + *len = size; + } + + SocketAddr::Netlink(name) => { + let size = core::mem::size_of::() as u32; + assert!(*len >= size); + + let mut target = unsafe { UserRef::::new(VirtAddr::new(addr as u64)) }; + *target = name; + *len = size; + } + + SocketAddr::Unix(name) => { + let size = core::mem::size_of::() as u32; + assert!(*len >= size); + + let mut target = unsafe { UserRef::::new(VirtAddr::new(addr as u64)) }; + *len = name.path_len() as u32 + core::mem::offset_of!(SocketAddrUnix, path) as u32; + *target = name; + } + } + + Ok(0) +} + +/// Create an unbound pair of connected sockets in a specified domain, of a +/// specified type, under the protocol optionally specified by the protocol +/// argument. The two sockets shall be identical. The file descriptors used +/// in referencing the created sockets shall be returned in fds[0] and fds[1]. +#[syscall] +pub fn socket_pair( + domain: usize, + type_and_flags: usize, + protocol: usize, + fds: &mut [i32; 2], +) -> Result { + let current_task = scheduler::get_scheduler().current_task(); + let sockfd_flags = SocketFlags::from_bits_truncate(type_and_flags).into(); + + let a = create_socket(domain, type_and_flags, protocol)?; + let b = create_socket(domain, type_and_flags, protocol)?; + + UnixSocket::connect_pair(&a, &b)?; + + fds[0] = current_task.file_table.open_file(a, sockfd_flags)? as i32; + fds[1] = current_task.file_table.open_file(b, sockfd_flags)? as i32; + Ok(0) +} diff --git a/src/aero_kernel/src/syscall/process.rs b/src/aero_kernel/src/syscall/process.rs index 95e5c77fbf8..f02fecb20ad 100644 --- a/src/aero_kernel/src/syscall/process.rs +++ b/src/aero_kernel/src/syscall/process.rs @@ -1,24 +1,22 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use aero_syscall::signal::{SigAction, SigProcMask}; -use aero_syscall::{MMapFlags, MMapProt, SysInfo, SyscallError, Utsname}; +use aero_syscall::*; use spin::{Mutex, Once}; use crate::acpi::aml; @@ -26,8 +24,9 @@ use crate::fs; use crate::fs::Path; use crate::mem::paging::VirtAddr; -use crate::userland::scheduler; +use crate::userland::scheduler::{self, ExitStatus}; use crate::userland::signals::SignalEntry; +use crate::userland::task::sessions::SESSIONS; use crate::userland::task::TaskId; use crate::utils::sync::IrqGuard; @@ -38,34 +37,34 @@ fn hostname() -> &'static Mutex { } #[syscall(no_return)] -pub fn exit(status: usize) -> Result { +pub fn exit(status: usize) -> Result { #[cfg(all(test, feature = "ci"))] crate::emu::exit_qemu(crate::emu::ExitStatus::Success); #[cfg(not(feature = "ci"))] { - log::trace!( - "exiting the process (pid={pid}) with status: {status}", - pid = scheduler::get_scheduler().current_task().pid().as_usize(), - status = status - ); + let current_task = scheduler::get_scheduler().current_task(); + let pid = current_task.pid().as_usize(); + let path = current_task.path(); - crate::unwind::unwind_stack_trace(); + log::trace!("exiting the process (pid={pid}, path={path:?}) with status: {status}"); - scheduler::get_scheduler().exit(status as isize); + crate::unwind::unwind_stack_trace(); + scheduler::get_scheduler().exit(ExitStatus::Normal(status as isize)); } } #[syscall] -pub fn uname(buffer: &mut Utsname) -> Result { +pub fn uname(buffer: &mut Utsname) -> Result { fn init_array(fixed: &mut [u8; 65], init: &'static str) { let init_bytes = init.as_bytes(); let len = init.len(); - fixed[..len].copy_from_slice(init_bytes) + fixed[..len].copy_from_slice(init_bytes); + fixed[len..].fill(0); } - init_array(&mut buffer.name, "Aero"); + init_array(&mut buffer.sysname, "Aero"); init_array(&mut buffer.nodename, "unknown"); init_array(&mut buffer.version, env!("CARGO_PKG_VERSION")); init_array( @@ -83,7 +82,7 @@ pub fn uname(buffer: &mut Utsname) -> Result { } #[syscall] -pub fn fork() -> Result { +pub fn fork() -> Result { let scheduler = scheduler::get_scheduler(); let forked = scheduler.current_task().fork(); @@ -92,7 +91,7 @@ pub fn fork() -> Result { } #[syscall] -pub fn clone(entry: usize, stack: usize) -> Result { +pub fn clone(entry: usize, stack: usize) -> Result { let scheduler = scheduler::get_scheduler(); let cloned = scheduler.current_task().clone_process(entry, stack); @@ -101,9 +100,11 @@ pub fn clone(entry: usize, stack: usize) -> Result { } #[syscall] -pub fn kill(pid: usize, signal: usize) -> Result { +pub fn kill(pid: usize, signal: usize) -> Result { // If pid is positive, then signal is sent to the process with that pid. if pid > 0 { + crate::unwind::unwind_stack_trace(); + let task = scheduler::get_scheduler() .find_task(TaskId::new(pid)) .ok_or(SyscallError::ESRCH)?; @@ -116,20 +117,7 @@ pub fn kill(pid: usize, signal: usize) -> Result { } #[syscall(no_return)] -pub fn exec( - path: &Path, - args: usize, - argc: usize, - envs: usize, - envc: usize, -) -> Result { - let mut path = path; - - // fixme!!!! before MERGE!!!! ANDYYYY - if path.as_str() == "/bin/sh" { - path = Path::new("/usr/bin/bash"); - } - +pub fn exec(path: &Path, args: usize, argc: usize, envs: usize, envc: usize) -> Result { let executable = fs::lookup_path(path)?; if executable.inode().metadata()?.is_directory() { @@ -151,24 +139,25 @@ pub fn exec( scheduler::get_scheduler() .current_task() - .exec(executable, argv, envv) + .exec(&executable, argv, envv) .expect("task: failed to exec task"); unreachable!() } #[syscall] -pub fn log(msg: &str) -> Result { +pub fn log(msg: &str) -> Result { log::debug!("{}", msg); Ok(0x00) } #[syscall] -pub fn waitpid(pid: usize, status: &mut u32, _flags: usize) -> Result { +pub fn waitpid(pid: usize, status: &mut u32, flags: usize) -> Result { + let flags = WaitPidFlags::from_bits_truncate(flags); let current_task = scheduler::get_scheduler().current_task(); - Ok(current_task.waitpid(pid as isize, status)?) + Ok(current_task.waitpid(pid as isize, status, flags)?) } #[syscall] @@ -179,7 +168,7 @@ pub fn mmap( flags: usize, fd: usize, offset: usize, -) -> Result { +) -> Result { let address = VirtAddr::new(address as u64); let protection = MMapProt::from_bits(protection).ok_or(SyscallError::EINVAL)?; let flags = MMapFlags::from_bits(flags).ok_or(SyscallError::EINVAL)?; @@ -192,8 +181,7 @@ pub fn mmap( .current_task() .file_table .get_handle(fd) - .ok_or(SyscallError::EBADF)? - .dirnode(), + .ok_or(SyscallError::EBADF)?, ); } @@ -209,7 +197,7 @@ pub fn mmap( } #[syscall] -pub fn munmap(address: usize, size: usize) -> Result { +pub fn munmap(address: usize, size: usize) -> Result { let address = VirtAddr::new(address as u64); if scheduler::get_scheduler() @@ -224,23 +212,52 @@ pub fn munmap(address: usize, size: usize) -> Result { } #[syscall] -pub fn backtrace() -> Result { +pub fn mprotect(ptr: usize, size: usize, prot: usize) -> Result { + let ptr = VirtAddr::new(ptr as _); + let prot = MMapProt::from_bits(prot).ok_or(SyscallError::EINVAL)?; + + let task = scheduler::get_scheduler().current_task(); + task.vm().mprotect(ptr, size, prot); + + Ok(0) +} + +#[syscall] +pub fn backtrace() -> Result { crate::unwind::unwind_stack_trace(); Ok(0) } +/// Enables syscall tracer for this process/thread. +/// +/// When the tracer is enabled for a process, it also applies to any child processes spawned by the +/// process. #[syscall] -pub fn getpid() -> Result { +pub fn trace() -> Result { + scheduler::get_scheduler().current_task().enable_systrace(); + Ok(0) +} + +#[syscall] +pub fn getpid() -> Result { Ok(scheduler::get_scheduler().current_task().pid().as_usize()) } #[syscall] -pub fn gettid() -> Result { +pub fn getppid() -> Result { + Ok(scheduler::get_scheduler() + .current_task() + .parent_pid() + .as_usize()) +} + +#[syscall] +pub fn gettid() -> Result { Ok(scheduler::get_scheduler().current_task().tid().as_usize()) } #[syscall] -pub fn gethostname(buffer: &mut [u8]) -> Result { +pub fn gethostname(buffer: &mut [u8]) -> Result { let hostname = hostname().lock(); let bytes = hostname.as_bytes(); @@ -248,20 +265,21 @@ pub fn gethostname(buffer: &mut [u8]) -> Result { Err(SyscallError::ENAMETOOLONG) } else { buffer[0..bytes.len()].copy_from_slice(bytes); + buffer[bytes.len()] = b'\0'; Ok(bytes.len()) } } #[syscall] -pub fn info(struc: &mut SysInfo) -> Result { +pub fn info(struc: &mut SysInfo) -> Result { struc.uptime = crate::arch::time::get_uptime_ticks() as i64; Ok(0x00) } #[syscall] -pub fn sethostname(name: &[u8]) -> Result { +pub fn sethostname(name: &[u8]) -> Result { match core::str::from_utf8(name) { Ok(name) => { *hostname().lock() = name.into(); @@ -273,7 +291,7 @@ pub fn sethostname(name: &[u8]) -> Result { } #[syscall] -pub fn sigprocmask(how: usize, set: *const u64, old_set: *mut u64) -> Result { +pub fn sigprocmask(how: usize, set: *const u64, old_set: *mut u64) -> Result { let set = if set.is_null() { None } else { @@ -302,7 +320,7 @@ pub fn sigaction( sigact: *mut SigAction, sigreturn: usize, old: *mut SigAction, -) -> Result { +) -> Result { let new = if sigact.is_null() { None } else { @@ -310,7 +328,7 @@ pub fn sigaction( }; let entry = if let Some(new) = new { - Some(SignalEntry::from_sigaction(*new, sigreturn)?) + Some(SignalEntry::from_sigaction(&*new, sigreturn)?) } else { None }; @@ -331,7 +349,7 @@ pub fn sigaction( } #[syscall(no_return)] -pub fn shutdown() -> Result { +pub fn shutdown() -> Result { fs::cache::dcache().log(); fs::cache::clear_inode_cache(); @@ -342,3 +360,63 @@ pub fn shutdown() -> Result { unreachable!("aml: failed to shutdown (enter state S5)") } + +#[syscall] +pub fn getpgid(pid: usize) -> Result { + let current_task = scheduler::current_thread(); + + // If `pid` is 0, the process ID of the calling process is used. + let task = if pid == 0 || pid == current_task.pid().as_usize() { + current_task + } else { + scheduler::get_scheduler() + .find_task(TaskId::new(pid)) + .ok_or(SyscallError::ESRCH)? + }; + + let group = SESSIONS.find_group(&task).unwrap(); + Ok(group.id()) +} + +#[syscall] +pub fn setpgid(pid: usize, pgid: usize) -> Result { + let current_task = scheduler::current_thread(); + let task = if pid == 0 || pid == current_task.pid().as_usize() { + current_task.clone() + } else { + let task = scheduler::get_scheduler() + .find_task(TaskId::new(pid)) + .ok_or(SyscallError::ESRCH)?; + + if let Some(parent) = task.get_parent() { + if parent.tid() != current_task.tid() { + return Err(SyscallError::EPERM); + } + } else { + return Err(SyscallError::EPERM); + } + + task + }; + + if task.is_session_leader() + || !task.is_process_leader() + || task.session_id() != current_task.session_id() + { + return Err(SyscallError::EPERM); + } + + log::error!("setpgid: is a stub! (pid={pid} pgid={pgid})"); + Ok(0) +} + +#[syscall] +pub fn setsid() -> Result { + let current_task = scheduler::get_scheduler().current_task(); + if current_task.is_group_leader() { + return Err(SyscallError::EPERM); + } + + SESSIONS.isolate(¤t_task); + Ok(0) +} diff --git a/src/aero_kernel/src/syscall/time.rs b/src/aero_kernel/src/syscall/time.rs index 32cae2b3dca..fb1c7cd6ecb 100644 --- a/src/aero_kernel/src/syscall/time.rs +++ b/src/aero_kernel/src/syscall/time.rs @@ -1,36 +1,37 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use aero_syscall::time::ITimerVal; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::time::{ITimerVal, ITIMER_REAL}; use aero_syscall::{SyscallError, TimeSpec}; +use alloc::sync::Arc; +use alloc::vec::Vec; use crate::userland::scheduler; -use crate::utils::CeilDiv; +use crate::userland::task::Task; +use crate::utils::sync::{IrqGuard, Mutex}; const CLOCK_TYPE_REALTIME: usize = 0; const CLOCK_TYPE_MONOTONIC: usize = 1; #[syscall] pub fn sleep(timespec: &TimeSpec) -> Result { - let duration = (timespec.tv_nsec as usize).ceil_div(1000000000) + timespec.tv_sec as usize; + let duration = (timespec.tv_nsec as usize).div_ceil(1000000000) + timespec.tv_sec as usize; - scheduler::get_scheduler().inner.sleep(Some(duration))?; + scheduler::get_scheduler().sleep(Some(duration))?; Ok(0x00) } @@ -61,16 +62,34 @@ pub fn gettime(clock: usize, timespec: &mut TimeSpec) -> Result>> = Mutex::new(Vec::new()); + +pub fn check_timers() { + // for task in TIMERS.lock_irq().iter() { + // task.signal(aero_syscall::signal::SIGALRM); + // } +} + #[syscall] pub fn setitimer( - _which: usize, + which: usize, _new_value: &ITimerVal, - _old_value: &mut ITimerVal, + _old_value: usize, // FIXME: Option<&mut ITimerVal> ) -> Result { - let scheduler = scheduler::get_scheduler(); - scheduler - .current_task() - .signal(aero_syscall::signal::SIGALRM); + let _guard = IrqGuard::new(); + + match which { + // The interval timer value is decremented in real time. The SIGALRM signal is + // generated for the process when this timer expires. + ITIMER_REAL => {} + + _ => unreachable!("setitimer: unimplemented timer (ty={which})"), + } + + TIMERS + .lock_irq() + .push(scheduler::get_scheduler().current_task()); + Ok(0) } diff --git a/src/aero_kernel/src/tests.rs b/src/aero_kernel/src/tests.rs index fba81d76bd6..53230b24cc1 100644 --- a/src/aero_kernel/src/tests.rs +++ b/src/aero_kernel/src/tests.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #[cfg(feature = "ci")] use crate::emu; diff --git a/src/aero_kernel/src/unwind.rs b/src/aero_kernel/src/unwind.rs index d8c76451db8..a6e7a4e7d7d 100644 --- a/src/aero_kernel/src/unwind.rs +++ b/src/aero_kernel/src/unwind.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::panic::PanicInfo; @@ -28,8 +26,8 @@ use xmas_elf::ElfFile; use crate::mem::paging::{Translate, VirtAddr}; use crate::mem::AddressSpace; -use crate::logger; -use crate::rendy; +use crate::userland::scheduler; +use crate::{logger, rendy}; use crate::arch::interrupts; @@ -63,7 +61,7 @@ pub fn prepare_panic() { } pub struct UnwindInfo { - kernel_elf: ElfFile<'static>, + pub kernel_elf: ElfFile<'static>, } impl UnwindInfo { @@ -73,6 +71,8 @@ impl UnwindInfo { } pub fn unwind_stack_trace() { + let _guard = IrqGuard::new(); + let mut address_space = AddressSpace::this(); let offset_table = address_space.offset_page_table(); @@ -82,7 +82,7 @@ pub fn unwind_stack_trace() { for section in kernel_elf.section_iter() { if section.get_type() == Ok(ShType::SymTab) { let section_data = section - .get_data(&kernel_elf) + .get_data(kernel_elf) .expect("Failed to get kernel section data information"); if let SectionData::SymbolTable64(symtab) = section_data { @@ -99,10 +99,10 @@ pub fn unwind_stack_trace() { } // Make sure the RBP is not NULL. If it is then we cannot do the stack unwinding/tracing - // as no frame pointers were emmited in this build. This should only occur if you + // as no frame pointers were emitted in this build. This should only occur if you // set the field `eliminate-frame-pointer` in the target file to true or manually resetting // the RBP to prevent backtrace to avoid address leaks (for example when jumping to userland). - // If thats the case we return (resumes the parent function). + // If that's the case we return (resumes the parent function). if rbp == 0x00 { log::trace!(""); return; @@ -112,15 +112,14 @@ pub fn unwind_stack_trace() { for depth in 0../*64*/16 { if let Some(rip_rbp) = rbp.checked_add(core::mem::size_of::()) { - if offset_table - .translate_addr(VirtAddr::new(rip_rbp as u64)) - .is_none() - { + let rip_rbp = VirtAddr::new(rip_rbp as u64); + + if offset_table.translate_addr(rip_rbp).is_none() || !rip_rbp.is_canonical() { log::trace!("{:>2}: ", depth); break; } - let rip = unsafe { *(rip_rbp as *const usize) }; + let rip = unsafe { *(rip_rbp.as_ptr::()) }; if rip == 0 { break; @@ -137,7 +136,7 @@ pub fn unwind_stack_trace() { let st_size = data.size() as usize; if rip >= st_value && rip < (st_value + st_size) { - let mangled_name = data.get_name(&kernel_elf).unwrap_or(""); + let mangled_name = data.get_name(kernel_elf).unwrap_or(""); let demangled_name = rustc_demangle::demangle(mangled_name); name = Some(demangled_name); @@ -146,25 +145,48 @@ pub fn unwind_stack_trace() { if let Some(name) = name { log::trace!("{:>2}: 0x{:016x} - {}", depth, rip, name); + } else if scheduler::is_initialized() { + if let Some((region, tag)) = scheduler::current_thread() + .mem_tags + .lock() + .iter() + .find(|(region, _tag)| region.contains(&rip)) + { + let resolved_addr = rip - region.start; + log::trace!( + "{depth:>2}: 0x{rip:016x} - " + ); + } else { + log::trace!("{depth:>2}: 0x{rip:016x} - "); + } } else { - log::trace!("{:>2}: 0x{:016x} - ", depth, rip); + log::trace!("{depth:>2}: 0x{rip:016x} - "); } } else { // RBP has been overflowed... break; } } + + // let thread = scheduler::current_thread(); + // let tags = thread.mem_tags.lock(); + // let mut tags = tags.iter().collect::>(); + // tags.sort_by(|x, y| x.0.start.cmp(&y.0.start)); + // for (x, s) in tags.iter() { + // log::trace!("{:#x}..{:#x} {s}", x.start, x.end); + // } } #[cfg(feature = "ci")] use crate::emu; +use crate::utils::sync::IrqGuard; #[panic_handler] -extern "C" fn rust_begin_unwind(info: &PanicInfo) -> ! { +fn rust_begin_unwind(info: &PanicInfo) -> ! { prepare_panic(); - let deafult_panic = &format_args!(""); - let panic_message = info.message().unwrap_or(deafult_panic); + let message = info.message(); + let location = info.location().unwrap(); // Get the CPU ID where this panic happened and if PANIC_HOOK_READY is false // then we cannot get the CPU where this panic happened. @@ -174,14 +196,8 @@ extern "C" fn rust_begin_unwind(info: &PanicInfo) -> ! { 0x00 }; - log::error!("cpu '{}' panicked at '{}'", cpu_id, panic_message); - - // Print the panic location if it is available. - if let Some(panic_location) = info.location() { - log::error!("{}", panic_location); - } - - // Add a new line to make the stack trace more readable. + log::error!("cpu '{cpu_id}' panicked at {location}:"); + log::error!("{message}"); log::error!(""); unwind_stack_trace(); diff --git a/src/aero_kernel/src/userland/mod.rs b/src/aero_kernel/src/userland/mod.rs index 904518d1c30..7b7853de708 100644 --- a/src/aero_kernel/src/userland/mod.rs +++ b/src/aero_kernel/src/userland/mod.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use crate::fs; use crate::fs::Path; @@ -23,13 +21,14 @@ use crate::fs::Path; pub mod scheduler; pub mod signals; pub mod task; +pub mod terminal; pub mod vm; pub fn run() -> fs::Result<()> { let init_path = Path::new("/usr/bin/init"); let init_inode = fs::lookup_path(init_path)?; - scheduler::get_scheduler().exec(init_inode, None, None); + scheduler::get_scheduler().exec(&init_inode, None, None); Ok(()) } @@ -38,6 +37,6 @@ pub fn run_tests() -> fs::Result<()> { let utest_path = Path::new("/usr/bin/utest"); let utest_inode = fs::lookup_path(utest_path)?; - scheduler::get_scheduler().exec(utest_inode, None, None); + scheduler::get_scheduler().exec(&utest_inode, None, None); Ok(()) } diff --git a/src/aero_kernel/src/userland/scheduler/mod.rs b/src/aero_kernel/src/userland/scheduler/mod.rs index 981ada53b1d..3b7ce6adb22 100644 --- a/src/aero_kernel/src/userland/scheduler/mod.rs +++ b/src/aero_kernel/src/userland/scheduler/mod.rs @@ -1,35 +1,37 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #[cfg(feature = "round-robin")] pub mod round_robin; +use core::ops; + use alloc::sync::Arc; use crate::arch::interrupts::{self, InterruptStack}; +use crate::fs::cache::DirCacheItem; +use crate::syscall::ExecArgs; use crate::utils::sync::Mutex; -use crate::{fs::cache::DirCacheItem, syscall::ExecArgs}; use spin::Once; use self::round_robin::RoundRobin; use super::signals::SignalResult; +use super::task::sessions::SESSIONS; use super::task::{Task, TaskId}; static SCHEDULER: Once = Once::new(); @@ -56,7 +58,7 @@ pub trait SchedulerInterface: Send + Sync { fn preempt(&self); /// Exits the current task. - fn exit(&self, status: isize) -> !; + fn exit(&self, status: ExitStatus) -> !; } struct TaskContainer(Mutex>>); @@ -70,7 +72,7 @@ impl TaskContainer { self.0.lock().insert(task_id, task); } - fn remove_task(&self, task: Arc) { + fn remove_task(&self, task: &Task) { self.0.lock().remove(&task.pid()); } } @@ -78,9 +80,15 @@ impl TaskContainer { unsafe impl Send for TaskContainer {} unsafe impl Sync for TaskContainer {} +#[derive(Debug, Clone)] +pub enum ExitStatus { + Normal(isize), + Signal(usize), +} + pub struct Scheduler { tasks: TaskContainer, - pub inner: Arc, + inner: Arc, } impl Scheduler { @@ -98,11 +106,12 @@ impl Scheduler { /// Registers the provided task in the schedulers queue. pub fn register_task(&self, task: Arc) { self.tasks.register_task(task.pid(), task.clone()); - self.inner.register_task(task.clone()); + SESSIONS.register_task(task.clone()); + self.inner.register_task(task); } #[inline] - pub fn exec(&self, executable: DirCacheItem, argv: Option, envv: Option) { + pub fn exec(&self, executable: &DirCacheItem, argv: Option, envv: Option) { self.inner .current_task() .exec(executable, argv, envv) @@ -115,27 +124,44 @@ impl Scheduler { self.inner.current_task() } - pub fn exit(&self, status: isize) -> ! { + pub fn exit(&self, status: ExitStatus) -> ! { let current_task = self.inner.current_task(); - self.tasks.remove_task(current_task); - + SESSIONS.remove_task(¤t_task); + self.tasks.remove_task(¤t_task); self.inner.exit(status) } pub fn log_ptable(&self) { self.tasks.0.lock().iter().for_each(|(pid, task)| { + let path: String = task + .path() + .map(|path| path.into()) + .unwrap_or("".into()); + log::info!( "task(pid={pid:?}, path={:?}, state={:?})", - task.path().unwrap_or(String::from("")), + path, task.state() ) }); } + pub fn for_each_task)>(&self, mut f: F) { + self.tasks.0.lock().iter().for_each(|(_, task)| f(task)); + } + /// Lookup a task by ID #[inline] pub fn find_task(&self, task_id: TaskId) -> Option> { - self.tasks.0.lock().get(&task_id).map(|task| task.clone()) + self.tasks.0.lock().get(&task_id).cloned() + } +} + +impl ops::Deref for Scheduler { + type Target = dyn SchedulerInterface; + + fn deref(&self) -> &Self::Target { + &*self.inner } } @@ -146,13 +172,18 @@ pub fn get_scheduler() -> &'static Scheduler { .expect("Attempted to get the scheduler before it was initialized") } +#[inline] +pub fn current_thread() -> Arc { + get_scheduler().current_task() +} + /// Returns true if the task scheduler has been initiaized. pub fn is_initialized() -> bool { SCHEDULER.get().is_some() } static SCHEDULER_VECTOR: Once = Once::new(); -const SCHEDULER_TIMER_US: usize = 20000; +const SCHEDULER_TIMER_US: usize = 5000; fn scheduler_irq_handler(_stack: &mut InterruptStack) { #[cfg(target_arch = "x86_64")] @@ -168,7 +199,7 @@ fn scheduler_irq_handler(_stack: &mut InterruptStack) { /// Initialize the scheduler and set up the scheduler interrupt. pub fn init() { - SCHEDULER.call_once(|| Scheduler::new()).inner.init(); + SCHEDULER.call_once(Scheduler::new).inner.init(); let scheduler_vector = interrupts::allocate_vector(); interrupts::register_handler(scheduler_vector, scheduler_irq_handler); diff --git a/src/aero_kernel/src/userland/scheduler/round_robin.rs b/src/aero_kernel/src/userland/scheduler/round_robin.rs index 8522624c208..2f61eebb4ba 100644 --- a/src/aero_kernel/src/userland/scheduler/round_robin.rs +++ b/src/aero_kernel/src/userland/scheduler/round_robin.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::sync::Arc; @@ -25,16 +23,16 @@ use crate::arch; use crate::userland::signals::{SignalError, SignalResult}; use crate::userland::task::{SchedTaskAdapter, Task, TaskState}; -use crate::utils::sync::IrqGuard; +use crate::utils::sync::{IrqGuard, WaitQueue}; use crate::utils::PerCpu; -use super::SchedulerInterface; +use super::{ExitStatus, SchedulerInterface}; /// Scheduler queue containing a vector of all of the task of the enqueued /// taskes. struct TaskQueue { /// The kernel idle task is a special kind of task that is run when - /// no taskes in the scheduler's queue are avaliable to execute. The idle task + /// no taskes in the scheduler's queue are available to execute. The idle task /// is to be created for each CPU. idle_task: Arc, preempt_task: Arc, @@ -44,6 +42,8 @@ struct TaskQueue { dead: LinkedList, awaiting: LinkedList, deadline_awaiting: LinkedList, + + dead_wq: WaitQueue, } impl TaskQueue { @@ -58,11 +58,13 @@ impl TaskQueue { dead: LinkedList::new(SchedTaskAdapter::new()), awaiting: LinkedList::new(SchedTaskAdapter::new()), deadline_awaiting: LinkedList::new(SchedTaskAdapter::new()), + + dead_wq: WaitQueue::new(), } } fn push_runnable(&mut self, task: Arc) { - debug_assert_eq!(task.link.is_linked(), false); // Make sure the task is not already linked + debug_assert!(!task.link.is_linked()); // Make sure the task is not already linked task.update_state(TaskState::Runnable); self.runnable.push_back(task); @@ -70,24 +72,26 @@ impl TaskQueue { fn push_dead(&mut self, task: Arc) { debug_assert_eq!(task.state(), TaskState::Runnable); - debug_assert_eq!(task.link.is_linked(), false); // Make sure the task is not already linked + debug_assert!(!task.link.is_linked()); // Make sure the task is not already linked self.dead.push_back(task); } fn push_deadline_awaiting(&mut self, task: Arc, duration: usize) { - debug_assert_eq!(task.link.is_linked(), false); // Make sure the task is not already linked + debug_assert!(!task.link.is_linked()); // Make sure the task is not already linked - task.update_state(TaskState::AwaitingIo); + task.update_state(TaskState::AwaitingIoDeadline); task.set_sleep_duration(crate::arch::time::get_uptime_ticks() + duration); self.deadline_awaiting.push_back(task); } fn push_awaiting(&mut self, task: Arc) { - debug_assert_eq!(task.link.is_linked(), false); // Make sure the task is not already linked + debug_assert!(!task.link.is_linked()); // Make sure the task is not already linked task.update_state(TaskState::AwaitingIo); + task.set_sleep_duration(0); + self.awaiting.push_back(task); } } @@ -107,20 +111,22 @@ impl RoundRobin { /// Creates a new instance of the round robin scheduler and return a /// reference-counting pointer to itself. pub fn new() -> Arc { - let this = Arc::new(Self { - queue: PerCpu::new(|| TaskQueue::new()), - }); - - this + Arc::new(Self { + queue: PerCpu::new(TaskQueue::new), + }) } fn sweep_dead(&self) { let _guard = IrqGuard::new(); let queue = self.queue.get_mut(); - if let Some(task) = queue.dead.pop_front() { + if queue.dead.is_empty() { + queue.dead_wq.insert(self.current_task()); + self.await_io().unwrap(); + } else if let Some(task) = queue.dead.pop_front() { task.update_state(TaskState::Zombie); - task.into_zombie(); + task.make_zombie(); + // TODO: assert strong count here } } @@ -136,7 +142,7 @@ impl RoundRobin { if task.load_sleep_duration() <= time { let ptr = cursor.remove().unwrap(); - assert_eq!(ptr.link.is_linked(), false); + assert!(!ptr.link.is_linked()); ptr.update_state(TaskState::Runnable); ptr.set_sleep_duration(0); @@ -174,15 +180,16 @@ impl RoundRobin { queue.preempt_task.arch_task_mut(), current.arch_task(), ); + return; } - } else { - queue.current_task = None; - core::mem::drop(guard); - arch::task::arch_task_spinup( - queue.preempt_task.arch_task_mut(), - queue.idle_task.arch_task(), - ); } + + queue.current_task = None; + core::mem::drop(guard); + arch::task::arch_task_spinup( + queue.preempt_task.arch_task_mut(), + queue.idle_task.arch_task(), + ); } } } @@ -207,8 +214,12 @@ impl SchedulerInterface for RoundRobin { let _guard = IrqGuard::new(); let queue = self.queue.get_mut(); - if task.state() == TaskState::AwaitingIo { - let mut cursor = unsafe { queue.awaiting.cursor_mut_from_ptr(task.as_ref()) }; + if task.state() == TaskState::AwaitingIo || task.state() == TaskState::AwaitingIoDeadline { + let mut cursor = if task.state() == TaskState::AwaitingIoDeadline { + unsafe { queue.deadline_awaiting.cursor_mut_from_ptr(task.as_ref()) } + } else { + unsafe { queue.awaiting.cursor_mut_from_ptr(task.as_ref()) } + }; if let Some(task) = cursor.remove() { queue.push_runnable(task); @@ -255,13 +266,12 @@ impl SchedulerInterface for RoundRobin { } fn preempt(&self) { - // We want to preempt under the following curcumstances: + // We want to preempt under the following circumstances: // - // 1. When a process switches from the running state to the waiting - // state. + // 1. When a process switches from the running state to the waiting state. // 2. When the timer interrupt fires. - // 3. When the process switches from the waiting state to the runnable state - // (for example, on completion of I/O operation). + // 3. When the process switches from the waiting state to the runnable state (for example, + // on completion of I/O operation). // 4. When the process is terminated. let guard = IrqGuard::new(); @@ -283,7 +293,7 @@ impl SchedulerInterface for RoundRobin { self.sleep(None) } - fn exit(&self, status: isize) -> ! { + fn exit(&self, status: ExitStatus) -> ! { let guard = IrqGuard::new(); let queue = self.queue.get_mut(); @@ -293,11 +303,10 @@ impl SchedulerInterface for RoundRobin { .expect("attempted to exit current task before it was initialized") .clone(); - current_task - .exit_status - .store(status, core::sync::atomic::Ordering::SeqCst); + current_task.exit_status.call_once(|| status); - queue.push_dead(current_task.clone()); + queue.push_dead(current_task); + queue.dead_wq.notify_all(); core::mem::drop(guard); self.preempt(); diff --git a/src/aero_kernel/src/userland/signals.rs b/src/aero_kernel/src/userland/signals.rs index 09e67996bab..52e030b7915 100644 --- a/src/aero_kernel/src/userland/signals.rs +++ b/src/aero_kernel/src/userland/signals.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use aero_syscall::signal::*; @@ -28,17 +26,18 @@ use bit_field::BitField; use aero_syscall::SyscallError; -use super::scheduler; +use super::scheduler::{self, ExitStatus}; use crate::fs::FileSystemError; use crate::utils::sync::{Mutex, MutexGuard}; mod default { use crate::userland::scheduler; + use crate::userland::scheduler::ExitStatus; #[derive(Copy, Clone, PartialEq)] pub enum Action { Ignore, - Handle(fn()), + Handle(fn(usize)), } /// Some of the default actions for the signals. @@ -80,15 +79,15 @@ mod default { Action::Ignore, // UNUSED ]; - fn terminate() { - scheduler::get_scheduler().exit(1); + fn terminate(signal: usize) { + scheduler::get_scheduler().exit(ExitStatus::Signal(signal)); } - fn terminate_thread() { + fn terminate_thread(_signal: usize) { unimplemented!() } - fn stop() { + fn stop(_signal: usize) { unimplemented!() } @@ -102,7 +101,7 @@ mod default { let action = DEFAULT_ACTIONS[signal]; if let Action::Handle(f) = action { - (f)(); + (f)(signal); } } } @@ -116,7 +115,7 @@ const IMMUTABLE_MASK: u64 = (1u64 << SIGSTOP) | (1u64 << SIGCONT) | (1u64 << SIG /// Returns [`true`] if the provided `signal` is overridable. fn can_override(signal: usize) -> bool { - IMMUTABLE_MASK.get_bit(signal) == false + !IMMUTABLE_MASK.get_bit(signal) } pub type SignalResult = core::result::Result; @@ -148,7 +147,7 @@ pub struct SignalEntry { impl SignalEntry { /// Create a new `SignalEntry` with the provided `sigaction` and `sigreturn`. pub fn from_sigaction( - sigaction: SigAction, + sigaction: &SigAction, sigreturn: usize, ) -> Result { Ok(SignalEntry { @@ -159,7 +158,7 @@ impl SignalEntry { }) } - pub fn into_sigaction(&self) -> SigAction { + pub fn sigaction(&self) -> SigAction { let handler: usize = self.handler.into(); SigAction { @@ -361,7 +360,10 @@ impl Signals { handler: Option, old: Option<&mut SigAction>, ) { - assert!(signal < SIGNAL_COUNT); + if signal >= SIGNAL_COUNT { + log::warn!("signal index is out of bounds"); + return; + } if !can_override(signal) { return; @@ -370,7 +372,7 @@ impl Signals { let mut signals = self.entries(); if let Some(old) = old { - *old = signals[signal].into_sigaction(); + *old = signals[signal].sigaction(); } if let Some(handler) = handler { @@ -393,12 +395,9 @@ impl Signals { /// Used to update or read the signal mask of a task. /// /// ## Notes - /// * If `old_set` is not `None`, the previous value of the signal mask is - /// stored in oldset. - /// - /// * If `set` is `None`, then the signal mask is unchanged (i.e., `how` is - /// ignored), but the current value of the signal mask is returned in `old_set` - /// (if it is not `None`). + /// * If `old_set` is not `None`, the previous value of the signal mask is stored in oldset. + /// * If `set` is `None`, then the signal mask is unchanged (i.e., `how` is ignored), but the + /// current value of the signal mask is returned in `old_set` (if it is not `None`). pub fn set_mask(&self, how: SigProcMask, set: Option, old_set: Option<&mut u64>) { if let Some(old) = old_set { *old = self.blocked_mask.load(Ordering::SeqCst); @@ -436,7 +435,7 @@ pub fn check_for_signals() -> Option<(usize, SignalEntry)> { // Check if a SIGKILL is pending, and if so, kill the task. if signals.is_pending(SIGKILL as u64) { signals.clear_pending(SIGKILL as u64); - scheduler::get_scheduler().exit(1); + scheduler::get_scheduler().exit(ExitStatus::Normal(1)); } for i in 0..SIGNAL_COUNT { diff --git a/src/aero_kernel/src/userland/task.rs b/src/aero_kernel/src/userland/task/mod.rs similarity index 52% rename from src/aero_kernel/src/userland/task.rs rename to src/aero_kernel/src/userland/task/mod.rs index 76fb159ffd6..d6b2a8615fe 100644 --- a/src/aero_kernel/src/userland/task.rs +++ b/src/aero_kernel/src/userland/task/mod.rs @@ -1,44 +1,50 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +pub mod sessions; + +use aero_syscall::WaitPidFlags; use alloc::sync::{Arc, Weak}; -use spin::RwLock; +use hashbrown::HashMap; +use spin::{Once, RwLock}; use core::cell::UnsafeCell; -use core::sync::atomic::{AtomicBool, AtomicIsize, AtomicU8, AtomicUsize, Ordering}; +use core::ops::Range; +use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering}; use crate::fs::cache::{DirCacheImpl, DirCacheItem}; +use crate::fs::path::PathBuf; use crate::fs::{self, FileSystem}; use crate::mem::paging::*; use crate::arch::task::ArchTask; use crate::fs::file_table::FileTable; -use crate::syscall::{ExecArgs, MessageQueue}; -use crate::utils::sync::{BlockQueue, Mutex}; +use crate::syscall::ipc::MessageQueue; +use crate::syscall::ExecArgs; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueError, WaitQueueFlags}; use crate::userland::signals::Signals; use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListLink}; -use super::scheduler; +use super::scheduler::{self, ExitStatus}; use super::signals::{SignalResult, TriggerResult}; +use super::terminal::TerminalDevice; use super::vm::Vm; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -67,6 +73,7 @@ pub enum TaskState { Runnable, Zombie, AwaitingIo, + AwaitingIoDeadline, } impl From for TaskState { @@ -75,6 +82,7 @@ impl From for TaskState { 0 => TaskState::Runnable, 1 => TaskState::Zombie, 2 => TaskState::AwaitingIo, + 3 => TaskState::AwaitingIoDeadline, _ => panic!("invalid task state"), } } @@ -86,39 +94,39 @@ struct Cwd { } impl Cwd { - fn new() -> RwLock { + fn new() -> Self { let root = fs::root_dir().clone(); let fs = root.inode().weak_filesystem().unwrap().upgrade().unwrap(); - RwLock::new(Self { + Self { inode: root, filesystem: fs, - }) + } } - fn fork(&self) -> RwLock { - RwLock::new(Self { + fn fork(&self) -> Self { + Self { inode: self.inode.clone(), filesystem: self.filesystem.clone(), - }) + } } } struct Zombies { list: Mutex>, - block: BlockQueue, + block: WaitQueue, } impl Zombies { fn new() -> Self { Self { list: Mutex::new(Default::default()), - block: BlockQueue::new(), + block: WaitQueue::new(), } } fn add_zombie(&self, zombie: Arc) { - assert_eq!(zombie.link.is_linked(), false); + assert!(!zombie.link.is_linked()); assert_eq!(zombie.state(), TaskState::Zombie); let mut list = self.list.lock(); @@ -126,19 +134,24 @@ impl Zombies { log::debug!("making process a zombie: (pid={:?})", zombie.pid()); list.push_back(zombie); - self.block.notify_complete(); + self.block.notify_all(); } - fn waitpid(&self, pids: &[usize], status: &mut u32) -> SignalResult { - let mut captured = (TaskId(0), 0); + fn waitpid( + &self, + pids: &[usize], + status: &mut u32, + flags: WaitPidFlags, + ) -> Result { + let mut captured = None; - self.block.block_on(&self.list, |l| { + self.block.wait(WaitQueueFlags::empty(), &self.list, |l| { let mut cursor = l.front_mut(); while let Some(t) = cursor.get() { for pid in pids { if t.pid().as_usize() == *pid { - captured = (t.pid(), t.exit_status()); + captured = Some((t.pid(), t.exit_status().clone())); cursor.remove(); return true; @@ -148,18 +161,32 @@ impl Zombies { cursor.move_next(); } + if flags.contains(WaitPidFlags::WNOHANG) { + return true; + } + false })?; - let (tid, st) = captured; + if let Some((tid, exit_status)) = captured { + // mlibc/abis/linux/wait.h (`W_EXITCODE`) + match exit_status { + ExitStatus::Normal(code) => { + *status = (code as u32) << 8; + } - // WIFEXITED: The child process has been terminated normally by - // either calling sys_exit() or returning from the main function. - *status = 0x200; - // The lower 8-bits are used to store the exit status. - *status |= st as u32 & 0xff; + ExitStatus::Signal(signal) => { + *status = signal as u32; + } + } - Ok(tid.as_usize()) + Ok(tid.as_usize()) + } else { + // If `WNOHANG` was specified in flags and there were no children in a waitable + // state, then waipid() returns 0 immediately. + *status = 0; + Ok(0) + } } } @@ -169,13 +196,12 @@ pub struct Task { arch_task: UnsafeCell, state: AtomicU8, - // Note: Aero implementes the threads and as standard processes. This - // means that when a new process is created its TID == PID and when a new - // thread is created then the PID of the thread will be the process leader's - // PID and the TID will be uniquely generated. pid: TaskId, tid: TaskId, + sid: AtomicUsize, + gid: AtomicUsize, + parent: Mutex>>, children: Mutex>, @@ -184,7 +210,7 @@ pub struct Task { sleep_duration: AtomicUsize, signals: Signals, - executable: Mutex>, + pub executable: Mutex>, pending_io: AtomicBool, pub(super) link: intrusive_collections::LinkedListLink, @@ -195,9 +221,15 @@ pub struct Task { pub message_queue: MessageQueue, - cwd: RwLock, + cwd: RwLock>, + + pub(super) exit_status: Once, + + controlling_terminal: Mutex>>, + systrace: AtomicBool, - pub(super) exit_status: AtomicIsize, + // for debugging only. may remove in the future. + pub mem_tags: Mutex, String>>, } impl Task { @@ -216,7 +248,9 @@ impl Task { message_queue: MessageQueue::new(), - tid: pid.clone(), + tid: pid, + sid: AtomicUsize::new(pid.as_usize()), + gid: AtomicUsize::new(pid.as_usize()), pid, executable: Mutex::new(None), @@ -230,13 +264,18 @@ impl Task { pending_io: AtomicBool::new(false), sleep_duration: AtomicUsize::new(0), - exit_status: AtomicIsize::new(0), + exit_status: Once::new(), children: Mutex::new(Default::default()), parent: Mutex::new(None), signals: Signals::new(), - cwd: Cwd::new(), + cwd: RwLock::new(None), + + systrace: AtomicBool::new(false), + controlling_terminal: Mutex::new(None), + + mem_tags: Mutex::new(HashMap::new()), }) } @@ -257,14 +296,16 @@ impl Task { vm: Arc::new(Vm::new()), state: AtomicU8::new(TaskState::Runnable as _), - tid: pid.clone(), + tid: pid, + gid: AtomicUsize::new(pid.as_usize()), + sid: AtomicUsize::new(pid.as_usize()), pid, link: Default::default(), clink: Default::default(), sleep_duration: AtomicUsize::new(0), - exit_status: AtomicIsize::new(0), + exit_status: Once::new(), executable: Mutex::new(None), pending_io: AtomicBool::new(false), @@ -273,11 +314,34 @@ impl Task { parent: Mutex::new(None), signals: Signals::new(), - cwd: Cwd::new(), + cwd: RwLock::new(None), + + systrace: AtomicBool::new(false), + controlling_terminal: Mutex::new(None), + + mem_tags: Mutex::new(HashMap::new()), }) } - fn make_child(&self, arch_task: UnsafeCell) -> Arc { + pub fn has_pending_io(&self) -> bool { + self.pending_io.load(Ordering::SeqCst) + } + + pub fn set_pending_io(&self, yes: bool) { + self.pending_io.store(yes, Ordering::SeqCst) + } + + pub fn signals(&self) -> &Signals { + &self.signals + } + + pub fn clone_process(&self, entry: usize, stack: usize) -> Arc { + let arch_task = UnsafeCell::new( + self.arch_task_mut() + .clone_process(entry, stack) + .expect("failed to fork arch task"), + ); + let pid = TaskId::allocate(); let this = Arc::new_cyclic(|sref| Self { @@ -285,54 +349,56 @@ impl Task { zombies: Zombies::new(), arch_task, - file_table: Arc::new(self.file_table.deep_clone()), + file_table: self.process_leader().file_table.clone(), message_queue: MessageQueue::new(), - vm: Arc::new(Vm::new()), + vm: self.process_leader().vm.clone(), state: AtomicU8::new(TaskState::Runnable as _), link: Default::default(), clink: Default::default(), sleep_duration: AtomicUsize::new(0), - exit_status: AtomicIsize::new(0), + exit_status: Once::new(), - tid: pid.clone(), + tid: pid, + sid: AtomicUsize::new(self.session_id()), + gid: AtomicUsize::new(self.group_id()), pid, executable: Mutex::new(self.executable.lock().clone()), pending_io: AtomicBool::new(false), children: Mutex::new(Default::default()), + // sus? fixme? parent: Mutex::new(None), - cwd: self.cwd.read().fork(), + cwd: RwLock::new(Some(self.cwd.read().as_ref().unwrap().fork())), signals: Signals::new(), + + systrace: AtomicBool::new(self.process_leader().systrace()), + controlling_terminal: Mutex::new( + self.process_leader() + .controlling_terminal + .lock_irq() + .clone(), + ), + + mem_tags: Mutex::new(self.mem_tags.lock().clone()), }); self.add_child(this.clone()); this.signals().copy_from(self.signals()); - this.vm.fork_from(self.vm()); - this.vm.log(); this } - pub fn has_pending_io(&self) -> bool { - self.pending_io.load(Ordering::SeqCst) - } - - pub fn set_pending_io(&self, yes: bool) { - self.pending_io.store(yes, Ordering::SeqCst) - } - - pub fn signals(&self) -> &Signals { - &self.signals - } + pub fn fork(&self) -> Arc { + let vm = Arc::new(Vm::new()); + let address_space = vm.fork_from(self.vm()); - pub fn clone_process(&self, entry: usize, stack: usize) -> Arc { let arch_task = UnsafeCell::new( self.arch_task_mut() - .clone_process(entry, stack) + .fork(address_space) .expect("failed to fork arch task"), ); @@ -343,18 +409,20 @@ impl Task { zombies: Zombies::new(), arch_task, - file_table: self.process_leader().file_table.clone(), + file_table: Arc::new(self.file_table.deep_clone()), message_queue: MessageQueue::new(), - vm: self.process_leader().vm.clone(), + vm, state: AtomicU8::new(TaskState::Runnable as _), link: Default::default(), clink: Default::default(), sleep_duration: AtomicUsize::new(0), - exit_status: AtomicIsize::new(0), + exit_status: Once::new(), - tid: pid.clone(), + tid: pid, + sid: AtomicUsize::new(self.session_id()), + gid: AtomicUsize::new(self.group_id()), pid, executable: Mutex::new(self.executable.lock().clone()), @@ -363,26 +431,20 @@ impl Task { children: Mutex::new(Default::default()), parent: Mutex::new(None), - cwd: self.cwd.read().fork(), + cwd: RwLock::new(Some(self.cwd.read().as_ref().unwrap().fork())), signals: Signals::new(), + + systrace: AtomicBool::new(self.systrace()), + controlling_terminal: Mutex::new(self.controlling_terminal.lock_irq().clone()), + + mem_tags: Mutex::new(self.mem_tags.lock().clone()), }); self.add_child(this.clone()); this.signals().copy_from(self.signals()); - this } - pub fn fork(&self) -> Arc { - let arch_task = UnsafeCell::new( - self.arch_task_mut() - .fork() - .expect("failed to fork arch task"), - ); - - self.make_child(arch_task) - } - fn this(&self) -> Arc { self.sref.upgrade().unwrap() } @@ -409,8 +471,8 @@ impl Task { children.push_back(child); } - fn exit_status(&self) -> isize { - self.exit_status.load(Ordering::SeqCst) + pub fn exit_status(&self) -> &ExitStatus { + self.exit_status.get().unwrap() } pub fn set_sleep_duration(&self, duration: usize) { @@ -421,7 +483,12 @@ impl Task { self.sleep_duration.load(Ordering::SeqCst) } - pub fn waitpid(&self, pid: isize, status: &mut u32) -> SignalResult { + pub fn waitpid( + &self, + pid: isize, + status: &mut u32, + flags: WaitPidFlags, + ) -> Result { if pid == -1 { // wait for any child process if no specific process is requested. // @@ -437,26 +504,38 @@ impl Task { .collect::>(); pids.extend(self.children.lock_irq().iter().map(|e| e.pid().as_usize())); - self.zombies.waitpid(&pids, status) + self.zombies.waitpid(&pids, status, flags) } else { - self.zombies.waitpid(&[pid as _], status) + self.zombies.waitpid(&[pid as _], status, flags) } } - pub fn path(&self) -> Option { - self.executable - .lock() - .as_ref() - .map(|e| e.absolute_path_str()) + pub fn path(&self) -> Option { + self.executable.lock().as_ref().map(|e| e.absolute_path()) } pub fn exec( &self, - executable: DirCacheItem, + executable: &DirCacheItem, argv: Option, envv: Option, ) -> Result<(), MapToError> { + if self.cwd.read().is_none() { + *self.cwd.write() = Some(Cwd::new()) + } + + // if executable.absolute_path_str().contains("gcc") + // || executable.absolute_path_str().contains("ls") + // { + // self.enable_systrace(); + // } + + *self.mem_tags.lock() = HashMap::new(); + self.file_table.close_on_exec(); + + self.file_table.log(); + *self.executable.lock() = Some(executable.clone()); let vm = self.vm(); @@ -483,16 +562,65 @@ impl Task { } pub(super) fn update_state(&self, state: TaskState) { - if state != TaskState::Runnable { + if state == TaskState::Zombie { + // [41] syscall/net.rs:178 (tid=33, pid=33) debug [aero_kernel/src/syscall/net.rs:178] + // current_task.file_table.open_file(entry, sockfd_flags) = Ok( 17, + // ) + // [41] syscall/process.rs:157 (tid=33, pid=33) debug mlibc: getsockopt() call with + // SOL_SOCKET and SO_TYPE is unimplemented, hardcoding SOCK_STREAM + // [41] syscall/process.rs:157 (tid=33, pid=33) debug mlibc: getsockopt() call with + // SOL_SOCKET and SO_KEEPALIVE is unimplemented, hardcoding 0 [41] syscall/ + // process.rs:157 (tid=33, pid=33) debug mlibc: setsockopt(SO_PASSCRED) is not + // implemented correctly [41] socket/netlink.rs:263 (tid=33, pid=33) warn + // netlink::send(flags=NOSIGNAL) [41] socket/netlink.rs:228 (tid=33, pid=33) + // debug [aero_kernel/src/socket/netlink.rs:228] message_hdr.iovecs_mut() = [ + // IoVec { + // base: 0x0000000000000000, + // len: 0, + // }, + // ] + // [42] syscall/process.rs:157 (tid=40, pid=40) debug mlibc: sys_setuid is a stub + // [42] syscall/process.rs:157 (tid=40, pid=40) debug In function mlock, file + // ../../../bundled/mlibc/options/posix/generic/sys-mman-stubs.cpp:22 + // __ensure(Library function fails due to missing sysdep) failed + // [42] syscall/process.rs:157 (tid=40, pid=40) debug mlibc: uselocale() is a no-op + // [42] syscall/process.rs:157 (tid=40, pid=40) debug mlibc: sys_setuid is a stub + // [42] syscall/process.rs:157 (tid=40, pid=40) debug mlibc: sys_seteuid is a stub + // [42] syscall/process.rs:157 (tid=40, pid=40) debug mlibc: sys_setgid is a stub + // [42] syscall/process.rs:157 (tid=40, pid=40) debug mlibc: sys_getegid is a stub + // [42] syscall/net.rs:178 (tid=40, pid=40) debug [aero_kernel/src/syscall/net.rs:178] + // current_task.file_table.open_file(entry, sockfd_flags) = Ok( 0, + // ) + // + // exit err 5 Input/output error + + // TODO: is_process_leader() && children.len() == 0 and then + // assert!(self.file_table.strong_count() == 1); + dbg!(Arc::strong_count(&self.file_table)); log::warn!( - "Task::update_state() updated the task state to {state:?}! (pid={:?}, tid={:?})", - self.pid, - self.tid + "HI MOM HI MOM HI MOM HI MOM: I HAVE {} STRONG AND {} WEAK REFERENCES", + Weak::strong_count(&self.sref), + Weak::weak_count(&self.sref) ); - - crate::unwind::unwind_stack_trace(); + if Arc::strong_count(&self.file_table) == 1 { + self.file_table.0.read().iter().for_each(|file| { + if let Some(handle) = file { + handle.inode().close(handle.flags()); + } + }); + } } + // if state != TaskState::Runnable { + // log::warn!( + // "Task::update_state() updated the task state to {state:?}! (pid={:?}, tid={:?})", + // self.pid, + // self.tid + // ); + + // crate::unwind::unwind_stack_trace(); + // } + self.state.store(state as _, Ordering::SeqCst); } @@ -505,32 +633,41 @@ impl Task { self.pid } + pub fn parent_pid(&self) -> TaskId { + if let Some(parent) = self.get_parent() { + parent.pid() + } else { + // On top of the family tree. + self.pid() + } + } + pub fn tid(&self) -> TaskId { self.tid } - pub fn get_cwd_dirent(&self) -> DirCacheItem { - self.cwd.read().inode.clone() + pub fn cwd_dirent(&self) -> DirCacheItem { + self.cwd.read().as_ref().unwrap().inode.clone() } - pub fn get_cwd(&self) -> String { - self.cwd.read().inode.absolute_path_str() + pub fn get_cwd(&self) -> PathBuf { + self.cwd.read().as_ref().unwrap().inode.absolute_path() } pub fn set_cwd(&self, cwd: DirCacheItem) { let filesystem = cwd.inode().weak_filesystem().unwrap().upgrade().unwrap(); - self.cwd.write().inode = cwd; - self.cwd.write().filesystem = filesystem; + self.cwd.write().as_mut().unwrap().inode = cwd; + self.cwd.write().as_mut().unwrap().filesystem = filesystem; } - fn get_parent(&self) -> Option> { + pub fn get_parent(&self) -> Option> { let parent = self.parent.lock(); parent.clone() } pub fn wake_up(&self) { - scheduler::get_scheduler().inner.wake_up(self.this()) + scheduler::get_scheduler().wake_up(self.this()) } pub fn is_process_leader(&self) -> bool { @@ -585,7 +722,8 @@ impl Task { } } - pub(super) fn into_zombie(&self) { + pub(super) fn make_zombie(&self) { + self.detach(); self.arch_task_mut().dealloc(); if let Some(parent) = self.get_parent() { @@ -593,10 +731,73 @@ impl Task { parent.zombies.add_zombie(self.this()); if self.is_process_leader() { - // parent.signal(aero_syscall::signal::SIGCHLD); + parent.signal(aero_syscall::signal::SIGCHLD); } } } + + pub fn systrace(&self) -> bool { + self.systrace.load(Ordering::SeqCst) + } + + pub fn enable_systrace(&self) { + self.systrace.store(true, Ordering::SeqCst); + } + + pub fn detach(&self) { + let mut controlling_terminal = self.controlling_terminal.lock_irq(); + + if let Some(term) = controlling_terminal.as_ref() { + term.detach(self.sref.upgrade().unwrap()); + *controlling_terminal = None; + } + } + + pub fn attach(&self, terminal: Arc) { + if self.is_session_leader() { + terminal.attach(self.sref.upgrade().unwrap()); + *self.controlling_terminal.lock_irq() = Some(terminal); + } else { + // FIXME: If its not the session leader then we needs to be a part of the the same + // session as the terminal's foreground group. + *self.controlling_terminal.lock_irq() = Some(terminal); + } + } + + /// Returns the controlling terminal of the task. + pub fn controlling_terminal(&self) -> Option> { + self.controlling_terminal.lock_irq().clone() + } + + /// Returns whether the task is the session leader (`pid` == `sid`). + pub fn is_session_leader(&self) -> bool { + self.session_id() == self.pid().as_usize() + } + + /// Returns whether the task is the group leader (`pid` == `gid`). + pub fn is_group_leader(&self) -> bool { + self.group_id() == self.pid().as_usize() + } + + /// Returns the group identifier of the task (`GID`). + pub fn group_id(&self) -> usize { + self.gid.load(Ordering::SeqCst) + } + + /// Returns the session identifier of the task (`SID`). + pub fn session_id(&self) -> usize { + self.sid.load(Ordering::SeqCst) + } + + /// Sets the session identifier of the task (`SID`) to `session_id`. + pub(super) fn set_session_id(&self, session_id: usize) { + self.sid.store(session_id, Ordering::SeqCst); + } + + /// Sets the group identifier of the task (`GID`) to `group_id`. + pub(super) fn set_group_id(&self, group_id: usize) { + self.gid.store(group_id, Ordering::SeqCst); + } } // SAFETY: It's alright to access [`Task`] through references from other diff --git a/src/aero_kernel/src/userland/task/sessions.rs b/src/aero_kernel/src/userland/task/sessions.rs new file mode 100644 index 00000000000..e6a8a003036 --- /dev/null +++ b/src/aero_kernel/src/userland/task/sessions.rs @@ -0,0 +1,188 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use alloc::sync::Arc; +use hashbrown::HashMap; + +use crate::utils::sync::Mutex; + +use super::{Task, TaskId}; + +/// Process Group +/// +/// A process group is a collection of one or more processes that are grouped together so that +/// they can be manipulated as a single entity. +pub struct Group { + /// Unique identifier of the process group. + id: usize, + /// Processes part of the process group. + tasks: Mutex>>, +} + +impl Group { + /// Creates a new process group. + pub fn new(leader: Arc) -> Arc { + leader.set_group_id(leader.pid().as_usize()); + + let id = leader.pid().as_usize(); + + let mut tasks = HashMap::new(); + tasks.insert(leader.pid(), leader); + + Arc::new(Self { + id, + tasks: Mutex::new(tasks), + }) + } + + pub fn id(&self) -> usize { + self.id + } + + pub fn register_task(&self, task: Arc) { + assert!(self.tasks.lock_irq().insert(task.pid(), task).is_none()); + } + + pub fn remove_task(&self, task: &Arc) { + assert!(self.tasks.lock_irq().remove(&task.pid()).is_some()); + } + + pub fn is_empty(&self) -> bool { + self.tasks.lock_irq().is_empty() + } + + pub fn signal(&self, target: usize) { + for (_, task) in self.tasks.lock_irq().iter() { + log::error!("Sending signal to task: {:?}", task.path()); + + task.signal(target); + } + } +} + +/// Process Session +pub struct Session { + groups: Mutex>>, +} + +impl Session { + /// Creates a new process session. + pub fn new(leader: Arc) -> Arc { + leader.set_session_id(leader.pid().as_usize()); + + let mut groups = HashMap::new(); + groups.insert(leader.pid().as_usize(), Group::new(leader)); + + Arc::new(Self { + groups: Mutex::new(groups), + }) + } + + pub fn find(&self, target: &Arc) -> Option> { + self.groups.lock_irq().get(&target.group_id()).cloned() + } + + pub fn register_task(&self, task: Arc) { + assert!(!task.is_session_leader()); + + let mut groups = self.groups.lock_irq(); + if let Some(group) = groups.get(&task.group_id()) { + assert!(!task.is_group_leader()); + group.register_task(task); + } else { + assert!(task.is_group_leader()); + groups.insert(task.group_id(), Group::new(task)); + } + } + + pub fn remove_task(&self, task: &Arc) { + let mut groups = self.groups.lock(); + let group = groups + .get(&task.group_id()) + .expect("Session::remove_task: ESRCH"); + + group.remove_task(task); + + if group.is_empty() { + assert!(task.is_group_leader()); + groups.remove(&task.group_id()); + } + } + + pub fn is_empty(&self) -> bool { + self.groups.lock_irq().is_empty() + } +} + +pub struct SessionList(Mutex>>); + +impl SessionList { + /// Creates and registers a new process session with the given `leader` as the leader task. + pub fn create_session(&self, leader: Arc) { + self.0 + .lock_irq() + .insert(leader.pid().as_usize(), Session::new(leader)); + } + + pub fn find_group(&self, target: &Arc) -> Option> { + self.0.lock_irq().get(&target.session_id())?.find(target) + } + + pub fn register_task(&self, task: Arc) { + assert!(task.is_process_leader()); + + let sessions = self.0.lock_irq(); + + if let Some(session) = sessions.get(&task.session_id()) { + session.register_task(task); + } else { + drop(sessions); + self.create_session(task); + } + } + + pub fn remove_task(&self, task: &Arc) { + let mut sessions = self.0.lock_irq(); + let session = sessions + .get(&task.session_id()) + .expect("SessionList::remove_task: ESRCH"); + + session.remove_task(task); + + if session.is_empty() { + assert!(task.is_session_leader()); + sessions.remove(&task.session_id()); + } + } + + pub fn isolate(&self, task: &Arc) { + assert!(!task.is_group_leader() && !task.is_session_leader()); + + let leader = task.process_leader(); + + { + let mut sessions = self.0.lock_irq(); + sessions.remove(&task.session_id()); + } + + self.create_session(leader) + } +} + +lazy_static::lazy_static! { + pub static ref SESSIONS: SessionList = SessionList(Mutex::new(HashMap::new())); +} diff --git a/src/aero_kernel/src/userland/terminal.rs b/src/aero_kernel/src/userland/terminal.rs new file mode 100644 index 00000000000..7d568d788a3 --- /dev/null +++ b/src/aero_kernel/src/userland/terminal.rs @@ -0,0 +1,189 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::{signal, Termios, TermiosIFlag, TermiosLFlag}; + +use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; + +use spin::RwLock; + +use crate::fs; +use crate::fs::inode::INodeInterface; +use crate::utils::sync::{Mutex, WaitQueue, WaitQueueFlags}; + +use super::signals::SignalError; +use super::task::sessions::{Group, SESSIONS}; +use super::task::Task; + +/// Terminal Device +#[downcastable] +pub trait TerminalDevice: Send + Sync + INodeInterface { + /// Called when a session leader is attached/connected to the terminal device. + /// + /// The processs group of `task` will be set as the active process group that is associated with + /// the terminal (foreground). + fn attach(&self, task: Arc); + fn detach(&self, task: Arc); +} + +#[derive(Debug, Copy, Clone)] +pub enum LineControl { + Echo(u8), +} + +/// Line Discipline +/// +/// The middle terminal subsystem layer, used to implement behavior common to terminal devices. +/// +/// For example, the line discipline handles special characters such as the interrupt character +/// (`Ctrl+C`), the erase character (Backspace or Delete), and the kill character (`Ctrl+U`) on +/// input. +pub struct LineDiscipline { + wq: WaitQueue, + buffer: Mutex>, + foreground: RwLock>, + // TODO: Make this private. + pub termios: Mutex, +} + +impl LineDiscipline { + /// Creates a new line discipline. + pub fn new() -> Self { + use aero_syscall::{TermiosCFlag, TermiosOFlag}; + + // converts `^X` into `X` + let ctrl = |c| (c as u8 - 0x40); + + let mut termios = Termios { + c_iflag: TermiosIFlag::ICRNL | TermiosIFlag::IXON, + c_oflag: TermiosOFlag::OPOST | TermiosOFlag::ONLCR, + c_cflag: TermiosCFlag::CS6 | TermiosCFlag::CS7 | TermiosCFlag::CREAD, + c_lflag: TermiosLFlag::ECHOKE + | TermiosLFlag::ECHOE + | TermiosLFlag::ECHOK + | TermiosLFlag::ECHO + | TermiosLFlag::ECHOCTL + | TermiosLFlag::ISIG + | TermiosLFlag::ICANON + | TermiosLFlag::IEXTEN, + c_line: 0, + c_cc: [0; 32], + c_ispeed: 0, + c_ospeed: 0, + }; + + termios.c_cc[aero_syscall::VINTR] = ctrl('C'); + termios.c_cc[aero_syscall::VQUIT] = ctrl('\\'); + termios.c_cc[aero_syscall::VERASE] = 127; // DEL character + termios.c_cc[aero_syscall::VKILL] = ctrl('U'); + termios.c_cc[aero_syscall::VEOF] = ctrl('D'); + termios.c_cc[aero_syscall::VMIN] = 1; + termios.c_cc[aero_syscall::VSTART] = ctrl('Q'); + termios.c_cc[aero_syscall::VSTOP] = ctrl('S'); + termios.c_cc[aero_syscall::VSUSP] = ctrl('Z'); + + Self { + wq: WaitQueue::new(), + buffer: Mutex::new(Vec::new()), + foreground: RwLock::new(Weak::default()), + termios: Mutex::new(termios), + } + } + + #[inline] + pub fn termios(&self) -> Termios { + self.termios.lock().clone() + } + + #[inline] + pub fn set_termios(&self, termios: Termios) { + *self.termios.lock() = termios; + } + + pub fn read(&self, target: &mut [u8]) -> fs::Result { + let mut buffer = self + .wq + .wait(WaitQueueFlags::empty(), &self.buffer, |buf| !buf.is_empty())?; + + let size = core::cmp::min(target.len(), buffer.len()); + target[..size].copy_from_slice(&buffer.drain(..size).collect::>()); + + Ok(size) + } + + pub fn write(&self, target: &[u8], callback: F) + where + F: Fn(LineControl), + { + let mut buffer = self.buffer.lock_irq(); + let termios = self.termios.lock(); + let should_echo = termios.c_lflag.contains(TermiosLFlag::ECHO); + + for byte in target { + match byte { + // ETX: End of Text (`Ctrl+C`) + 0x3 if termios.is_cooked() => { + if let Some(foreground) = self.foreground() { + foreground.signal(signal::SIGINT); + } + } + + b'\r' if termios.c_iflag.contains(TermiosIFlag::ICRNL) => { + buffer.push(b'\n'); + + if should_echo { + callback(LineControl::Echo(b'\r')); + callback(LineControl::Echo(b'\n')); + } + } + + byte if termios.is_cooked() => { + buffer.push(*byte); + + if should_echo { + callback(LineControl::Echo(*byte)) + } + } + + // In raw mode: + _ => buffer.push(*byte), + } + } + + drop(buffer); + self.wq.notify_all(); + } + + pub fn foreground(&self) -> Option> { + self.foreground.read().upgrade() + } + + pub fn set_foreground(&self, task: &Arc) { + *self.foreground.write() = Arc::downgrade(&SESSIONS.find_group(task).unwrap()); + } + + /// Returns whether the line discipline buffer is empty. + pub fn is_empty(&self) -> bool { + self.buffer.lock_irq().is_empty() + } + + /// Returns the line discipline's wait queue. + pub fn wait_queue(&self) -> &WaitQueue { + &self.wq + } +} diff --git a/src/aero_kernel/src/userland/vm.rs b/src/aero_kernel/src/userland/vm.rs index 88829b0f7a8..458c3dc6142 100644 --- a/src/aero_kernel/src/userland/vm.rs +++ b/src/aero_kernel/src/userland/vm.rs @@ -1,46 +1,90 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::fmt::Write; +use core::ops::Range; -use aero_syscall::{MMapFlags, MMapProt}; +use aero_syscall::{MMapFlags, MMapProt, OpenFlags}; use alloc::boxed::Box; use alloc::collections::linked_list::CursorMut; use alloc::collections::LinkedList; +use alloc::sync::Arc; +use hashbrown::HashMap; use xmas_elf::header::*; use xmas_elf::program::*; use xmas_elf::*; use crate::arch::task::userland_last_address; -use crate::fs; -use crate::fs::cache::DirCacheImpl; -use crate::fs::cache::DirCacheItem; -use crate::fs::FileSystemError; -use crate::fs::Path; -use crate::mem; +use crate::fs::block::PageCacheItem; +use crate::fs::cache::{DirCacheImpl, DirCacheItem}; +use crate::fs::file_table::FileHandle; +use crate::fs::inode::MMapPage; +use crate::fs::{FileSystemError, Path}; use crate::mem::paging::*; use crate::mem::AddressSpace; +use crate::{fs, mem}; use crate::syscall::ExecArgs; -use crate::utils::sync::Mutex; +use crate::utils::sync::BMutex; + +bitflags::bitflags! { + #[derive(Debug, Copy, Clone, PartialEq)] + pub struct VmFlag: u8 { + // currently active flags + const READ = MMapProt::PROT_READ.bits() as _; + const WRITE = MMapProt::PROT_WRITE.bits() as _; + const EXEC = MMapProt::PROT_EXEC.bits() as _; + + // limits + const MAY_READ = 1 << 3; + const MAY_WRITE = 1 << 4; + const MAY_EXEC = 1 << 5; + + const SHARED = 1 << 6; + } +} + +const VM_PROT_MASK: VmFlag = + VmFlag::from_bits_retain(VmFlag::READ.bits() | VmFlag::WRITE.bits() | VmFlag::EXEC.bits()); + +impl From for VmFlag { + #[inline] + fn from(value: MMapProt) -> Self { + Self::from_bits_retain(value.bits().try_into().unwrap()) + } +} + +impl From for PageTableFlags { + fn from(flags: VmFlag) -> Self { + let mut value = PageTableFlags::empty(); + + if !flags.contains(VmFlag::EXEC) { + value.insert(PageTableFlags::NO_EXECUTE); + } + + if flags.contains(VmFlag::WRITE) { + value.insert(PageTableFlags::WRITABLE); + } + + value + } +} const ELF_HEADER_MAGIC: [u8; 4] = [0x7f, b'E', b'L', b'F']; @@ -49,7 +93,7 @@ const ELF_PT2_64_SIZE: usize = core::mem::size_of::>(); #[derive(Debug)] pub enum ElfLoadError { - /// Unexpected file system error occured on an IO operation on the file. + /// Unexpected file system error occurred on an IO operation on the file. IOError(FileSystemError), /// The PT1 header has an invalid magic number. InvalidMagic, @@ -57,20 +101,20 @@ pub enum ElfLoadError { InvalidClass, /// The provided program header index is invalid. InvalidProgramHeaderIndex, - /// Unexpected file system error occured when memory mapping an + /// Unexpected file system error occurred when memory mapping an /// ELF segment. MemoryMapError, } -fn parse_elf_header<'header>(file: DirCacheItem) -> Result, ElfLoadError> { +fn parse_elf_header<'header>(file: &DirCacheItem) -> Result, ElfLoadError> { // 1. Read the ELF PT1 header: - let mut pt1_hdr_slice = Box::leak(mem::alloc_boxed_buffer::(ELF_PT1_SIZE)); + let pt1_hdr_slice = Box::leak(mem::alloc_boxed_buffer::(ELF_PT1_SIZE)); file.inode() - .read_at(0, &mut pt1_hdr_slice) - .map_err(|err| ElfLoadError::IOError(err))?; + .read_at(OpenFlags::empty(), 0, pt1_hdr_slice) + .map_err(ElfLoadError::IOError)?; - let pt1_header: &'header _ = unsafe { &*(pt1_hdr_slice.as_ptr() as *const HeaderPt1) }; + let pt1_header: &'header _ = unsafe { &*pt1_hdr_slice.as_ptr().cast::() }; // 2. Ensure that the header has the correct magic number: if pt1_header.magic != ELF_HEADER_MAGIC { @@ -80,14 +124,14 @@ fn parse_elf_header<'header>(file: DirCacheItem) -> Result, ElfL let pt2_header = match pt1_header.class() { // 3. Read the 64-bit PT2 header: Class::SixtyFour => { - let mut pt2_hdr_slice = Box::leak(mem::alloc_boxed_buffer::(ELF_PT2_64_SIZE)); + let pt2_hdr_slice = Box::leak(mem::alloc_boxed_buffer::(ELF_PT2_64_SIZE)); file.inode() - .read_at(ELF_PT1_SIZE, &mut pt2_hdr_slice) - .map_err(|err| ElfLoadError::IOError(err))?; + .read_at(OpenFlags::empty(), ELF_PT1_SIZE, pt2_hdr_slice) + .map_err(ElfLoadError::IOError)?; let pt2_header_ptr = pt2_hdr_slice.as_ptr(); - let pt2_header: &'header _ = unsafe { &*(pt2_header_ptr as *const HeaderPt2_) }; + let pt2_header: &'header _ = unsafe { &*pt2_header_ptr.cast::>() }; Ok(HeaderPt2::Header64(pt2_header)) } @@ -97,7 +141,7 @@ fn parse_elf_header<'header>(file: DirCacheItem) -> Result, ElfL unimplemented!("parse_elf_header: 32-bit executables are not implemented") } - // SAFTEY: ensure the PT1 header has a valid class. + // SAFETY: ensure the PT1 header has a valid class. Class::None | Class::Other(_) => Err(ElfLoadError::InvalidClass), }?; @@ -108,13 +152,13 @@ fn parse_elf_header<'header>(file: DirCacheItem) -> Result, ElfL } fn parse_program_header<'pheader>( - file: DirCacheItem, + file: &DirCacheItem, header: Header<'pheader>, index: u16, ) -> Result, ElfLoadError> { let pt2 = &header.pt2; - // SAFTEY: ensure that the provided program header index is valid. + // SAFETY: ensure that the provided program header index is valid. if !(index < pt2.ph_count() && pt2.ph_offset() > 0 && pt2.ph_entry_size() > 0) { return Err(ElfLoadError::InvalidProgramHeaderIndex); } @@ -124,28 +168,28 @@ fn parse_program_header<'pheader>( let size = pt2.ph_entry_size() as usize; // 2. Read the 64-bit program header: - let mut phdr_buffer = Box::leak(mem::alloc_boxed_buffer::(size)); + let phdr_buffer = Box::leak(mem::alloc_boxed_buffer::(size)); file.inode() - .read_at(start, &mut phdr_buffer) - .map_err(|err| ElfLoadError::IOError(err))?; + .read_at(OpenFlags::empty(), start, phdr_buffer) + .map_err(ElfLoadError::IOError)?; let phdr_ptr = phdr_buffer.as_ptr(); match header.pt1.class() { // 3. Cast and return the 64-bit program header: Class::SixtyFour => { - let phdr: &'pheader _ = unsafe { &*(phdr_ptr as *const ProgramHeader64) }; + let phdr: &'pheader _ = unsafe { &*phdr_ptr.cast::() }; Ok(ProgramHeader::Ph64(phdr)) } // 3. Cast and return the 32-bit program header: Class::ThirtyTwo => { - let phdr: &'pheader _ = unsafe { &*(phdr_ptr as *const ProgramHeader32) }; + let phdr: &'pheader _ = unsafe { &*phdr_ptr.cast::() }; Ok(ProgramHeader::Ph32(phdr)) } - // SAFTEY: ensure the PT1 header has a valid class. + // SAFETY: ensure the PT1 header has a valid class. Class::None | Class::Other(_) => Err(ElfLoadError::InvalidClass), } } @@ -156,9 +200,8 @@ struct Shebang { } impl Shebang { - fn new(path: String, argument: String) -> Result { - let path = Path::new(&path); - let interpreter = fs::lookup_path(path).map_err(|err| ElfLoadError::IOError(err))?; + fn new>(path: P, argument: String) -> Result { + let interpreter = fs::lookup_path(path.as_ref()).map_err(ElfLoadError::IOError)?; Ok(Self { interpreter, @@ -169,18 +212,18 @@ impl Shebang { /// Returns [`true`] if the provided executable (`bin`) contains a shebang /// at the start. -fn contains_shebang(bin: DirCacheItem) -> Result { +fn contains_shebang(bin: &DirCacheItem) -> Result { let shebang = &mut [0u8; 2]; bin.inode() - .read_at(0, shebang) - .map_err(|err| ElfLoadError::IOError(err))?; + .read_at(OpenFlags::empty(), 0, shebang) + .map_err(ElfLoadError::IOError)?; - Ok(shebang[0] == '#' as u8 && shebang[1] == '!' as u8) + Ok(shebang[0] == b'#' && shebang[1] == b'!') } -fn parse_shebang(bin: DirCacheItem) -> Result, ElfLoadError> { - if !contains_shebang(bin.clone())? { +fn parse_shebang(bin: &DirCacheItem) -> Result, ElfLoadError> { + if !contains_shebang(bin)? { return Ok(None); } @@ -193,8 +236,8 @@ fn parse_shebang(bin: DirCacheItem) -> Result, ElfLoadError> { let c = &mut [0u8; 1]; bin.inode() - .read_at(idx, c) - .map_err(|err| ElfLoadError::IOError(err))?; + .read_at(OpenFlags::empty(), idx, c) + .map_err(ElfLoadError::IOError)?; Ok(c[0] as char) }; @@ -245,7 +288,7 @@ pub struct Elf<'this> { impl<'this> Elf<'this> { fn new(file: DirCacheItem) -> Result { - let header = parse_elf_header(file.clone())?; + let header = parse_elf_header(&file)?; Ok(Self { header, file }) } @@ -283,8 +326,7 @@ impl<'this> Iterator for ProgramHeaderIter<'this> { } // Parse and return the program header. - let result = - parse_program_header(self.file.clone(), self.header, self.next_index as u16).ok(); + let result = parse_program_header(&self.file, self.header, self.next_index as u16).ok(); // Increment the next index. self.next_index += 1; @@ -292,25 +334,9 @@ impl<'this> Iterator for ProgramHeaderIter<'this> { } } -impl From for PageTableFlags { - fn from(e: MMapProt) -> Self { - let mut res = PageTableFlags::empty(); - - if !e.contains(MMapProt::PROT_EXEC) { - res.insert(PageTableFlags::NO_EXECUTE); - } - - if e.contains(MMapProt::PROT_WRITE) { - res.insert(PageTableFlags::WRITABLE); - } - - res - } -} - enum UnmapResult { None, - Parital(Mapping), + Partial(Mapping), Full, Start, End, @@ -331,28 +357,52 @@ pub struct MMapFile { offset: usize, file: DirCacheItem, size: usize, + mappings: HashMap, } impl MMapFile { #[inline] fn new(file: DirCacheItem, offset: usize, size: usize) -> Self { - Self { file, offset, size } + Self { + offset, + file, + size, + mappings: HashMap::new(), + } } } #[derive(Clone)] -struct Mapping { - protection: MMapProt, - flags: MMapFlags, +pub struct Mapping { + flags: VmFlag, - start_addr: VirtAddr, - end_addr: VirtAddr, + pub start_addr: VirtAddr, + pub end_addr: VirtAddr, - file: Option, + pub file: Option, + refresh_flags: bool, } impl Mapping { - /// Handler routine for private anonymous pages. Since its an annonymous page is not + pub fn set_protection(&mut self, protection: MMapProt) -> aero_syscall::Result<()> { + if (protection.contains(MMapProt::PROT_READ) && !self.flags.contains(VmFlag::MAY_READ)) + || (protection.contains(MMapProt::PROT_WRITE) + && !self.flags.contains(VmFlag::MAY_WRITE)) + || (protection.contains(MMapProt::PROT_EXEC) && !self.flags.contains(VmFlag::MAY_EXEC)) + { + return Err(aero_syscall::SyscallError::EACCES); + } + + self.flags = (self.flags & !VM_PROT_MASK) | protection.into(); + Ok(()) + } + + #[inline] + pub fn protection(&self) -> VmFlag { + self.flags & VM_PROT_MASK + } + + /// Handler routine for private anonymous pages. Since its an anonymous page is not /// backed by a file, we have to alloctate a frame and map it at the faulted address. fn handle_pf_private_anon( &mut self, @@ -363,12 +413,6 @@ impl Mapping { let addr_aligned = address.align_down(Size4KiB::SIZE); if !reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) { - log::trace!( - " - private R: {:#x}..{:#x}", - addr_aligned, - addr_aligned + Size4KiB::SIZE - ); - let frame: PhysFrame = PhysFrame::containing_address(pmm_alloc(BuddyOrdering::Size4KiB)); @@ -379,9 +423,7 @@ impl Mapping { // NOTE: We dont need to remove the writeable flag from this mapping, since // the writeable flag will be removed from the parent and child on fork so, // the mapping gets copied on write. - PageTableFlags::USER_ACCESSIBLE - | PageTableFlags::PRESENT - | self.protection.into(), + PageTableFlags::USER_ACCESSIBLE | PageTableFlags::PRESENT | self.flags.into(), ) } .expect("Failed to identity map userspace private mapping") @@ -389,16 +431,29 @@ impl Mapping { true } else if reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) { - log::trace!( - " - private COW: {:#x}..{:#x}", - addr_aligned, - addr_aligned + Size4KiB::SIZE - ); - self.handle_cow(offset_table, addr_aligned, false) } else { - log::error!(" - present page read failed"); - false + if !self.refresh_flags { + return false; + } + + unsafe { + // The page is present but most likely the flags need to be updated after + // mprotect(2). + let page: Page = Page::containing_address(address); + offset_table + .update_flags( + page, + PageTableFlags::USER_ACCESSIBLE + | PageTableFlags::PRESENT + | self.flags.into(), + ) + .unwrap() + .flush(); + } + + self.refresh_flags = false; + true } } @@ -409,57 +464,185 @@ impl Mapping { &mut self, offset_table: &mut OffsetPageTable, reason: PageFaultErrorCode, - address: VirtAddr, + addr: VirtAddr, ) -> bool { - if let Some(mmap_file) = self.file.as_mut() { + if let Some(file) = self.file.as_ref() { let offset = align_down( - (address - self.start_addr) + mmap_file.offset as u64, + (addr - self.start_addr) + file.offset as u64, Size4KiB::SIZE, ); - let address = address.align_down(Size4KiB::SIZE); - let size = core::cmp::min( - Size4KiB::SIZE, - mmap_file.size as u64 - (address - self.start_addr), - ); + let addr = addr.align_down(Size4KiB::SIZE); + let size = Size4KiB::SIZE.min(file.size as u64 - (addr - self.start_addr)); - if !reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) { - // We are writing to private file mapping so copy the content of the page. - log::trace!( - " - private file R: {:?}..{:?} (offset={:#x})", - address, - address + size, - offset + return if self.flags.contains(VmFlag::SHARED) { + self.handle_pf_shared_file(offset_table, reason, addr, offset as _, size as _) + } else { + self.handle_pf_private_file(offset_table, reason, addr, offset as _, size as _) + }; + } + + false + } + + fn handle_pf_private_file( + &mut self, + offset_table: &mut OffsetPageTable, + reason: PageFaultErrorCode, + + addr: VirtAddr, + offset: usize, + size: usize, + ) -> bool { + let mmap_file = self.file.as_mut().unwrap(); + let page_cache = if let MMapPage::PageCache(page_cache) = + mmap_file.file.inode().mmap_v2(offset).unwrap() + { + page_cache + } else { + todo!() + }; + + if !reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) + && !reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) + { + let frame = if size == Size4KiB::SIZE as usize { + page_cache.page() + } else { + // The end needs to be zeroed out so we cannot directly map the cached page. + let page: Page = Page::containing_address(page_cache.data_addr().as_hhdm_virt()); + + let new_frame: PhysFrame = PhysFrame::containing_address( + FRAME_ALLOCATOR + .alloc_zeroed(Size4KiB::SIZE as usize) + .unwrap(), ); - let frame = mmap_file - .file - .inode() - .mmap(offset as _, size as _, self.flags) - .expect("handle_pf_file: file does not support mmap"); + let new_slice = new_frame.as_slice_mut::(); + new_slice[..size].copy_from_slice(unsafe { + core::slice::from_raw_parts(page.start_address().as_ptr::(), size) + }); + + new_frame + }; + + unsafe { + offset_table.map_to( + Page::containing_address(addr), + frame, + PageTableFlags::PRESENT + | PageTableFlags::USER_ACCESSIBLE + | (self.flags & !VmFlag::WRITE).into(), + ) + } + .expect("failed to map allocated frame for private file read") + .flush(); + + true + } else if !reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) + && reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) + { + // We are writing to private file mapping so copy the content of the page. + let frame = mmap_file + .file + .inode() + .mmap(offset, size, MMapFlags::empty()) + .expect("handle_pf_file: file does not support mmap"); + + unsafe { + offset_table.map_to( + Page::containing_address(addr), + frame, + PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | self.flags.into(), + ) + } + .expect("failed to map allocated frame for private file read") + .flush(); + + assert!(mmap_file.mappings.get(&addr).is_none()); + true + } else if reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) + && reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) + { + if self.handle_cow(offset_table, addr, true) { + self.file.as_mut().unwrap().mappings.remove(&addr); + return true; + } + + false + } else { + log::error!(" - present page read failed"); + false + } + } + + fn handle_pf_shared_file( + &mut self, + offset_table: &mut OffsetPageTable, + reason: PageFaultErrorCode, + + addr: VirtAddr, + offset: usize, + _size: usize, + ) -> bool { + let mmap_file = self.file.as_mut().unwrap(); + let mmap_page = mmap_file.file.inode().mmap_v2(offset).unwrap(); + + if reason.contains(PageFaultErrorCode::PROTECTION_VIOLATION) { + if reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) { + return false; + } + } else if let MMapPage::PageCache(page_cache) = &mmap_page { + mmap_file.mappings.insert(addr, page_cache.clone()); + } + + match mmap_page { + MMapPage::PageCache(page_cache) => { + if reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) { + unsafe { + offset_table.map_to( + Page::containing_address(addr), + page_cache.page(), + PageTableFlags::PRESENT + | PageTableFlags::USER_ACCESSIBLE + | self.flags.into(), + ) + } + .unwrap() + .flush(); + + page_cache.mark_dirty(); + } else { + unsafe { + offset_table.map_to( + Page::containing_address(addr), + page_cache.page(), + PageTableFlags::PRESENT + | PageTableFlags::USER_ACCESSIBLE + | (self.flags & !VmFlag::WRITE).into(), + ) + } + .unwrap() + .flush(); + } + } + MMapPage::Direct(frame) => { unsafe { offset_table.map_to( - Page::containing_address(address), + Page::containing_address(addr), frame, PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE - | self.protection.into(), + | self.flags.into(), ) } - .expect("failed to map allocated frame for private file read") + .unwrap() .flush(); - - true - } else if reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) { - self.handle_cow(offset_table, address, true) - } else { - log::error!(" - present page read failed"); - false } - } else { - false } + + true } /// Copies the contents of the `page` page to a newly allocated frame and maps it to @@ -467,7 +650,7 @@ impl Mapping { fn map_copied( offset_table: &mut OffsetPageTable, page: Page, - protection: MMapProt, + flags: VmFlag, ) -> Result<(), MapToError> { // Allocate a new frame to hold the contents. let new_frame: PhysFrame = FRAME_ALLOCATOR @@ -494,7 +677,7 @@ impl Mapping { .map_to( page, new_frame, - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | protection.into(), + PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | flags.into(), )? .flush(); } @@ -502,10 +685,10 @@ impl Mapping { Ok(()) } - /// Handler routine for a COW (Copy-On-Write) pages. A COW page is shared between multiple processes - /// until a write occurs after which a private copy is made for the writing process. A COW page - /// is recognised because the VMA for the region is marked writable even though the individual page - /// table entry is not. + /// Handler routine for a COW (Copy-On-Write) pages. A COW page is shared between multiple + /// processes until a write occurs after which a private copy is made for the writing + /// process. A COW page is recognised because the VMA for the region is marked writable even + /// though the individual page table entry is not. /// /// ## Panics /// * The provided `address` is not aligned to a page boundary. @@ -525,31 +708,26 @@ impl Mapping { if let Some(vm_frame) = phys_addr.as_vm_frame() { if vm_frame.ref_count() > 1 || copy { // This page is used by more then one process, so make it a private copy. - log::trace!(" - making {:?} into a private copy", page); - Self::map_copied(offset_table, page, self.protection).unwrap(); + Self::map_copied(offset_table, page, self.flags).unwrap(); } else { // This page is used by only one process, so make it writable. - log::trace!(" - making {:?} writable", page); - unsafe { offset_table.update_flags( page, PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE - | self.protection.into(), + | self.flags.into(), ) } .unwrap() .flush(); } - true - } else { - false + return true; } - } else { - false } + + false } fn unmap( @@ -558,16 +736,17 @@ impl Mapping { start: VirtAddr, end: VirtAddr, ) -> Result { - let mut unmap_range_inner = |range| -> Result<(), UnmapError> { - match offset_table.unmap_range(range, Size4KiB::SIZE) { - Ok(_) => Ok(()), - - // its fine since technically we are not actually allocating the range - // and they are just allocated on faults. So there might be a chance where we - // try to unmap a region that is mapped but not actually allocated. - Err(UnmapError::PageNotMapped) => Ok(()), - Err(err) => return Err(err), + let mut unmap_range_inner = |range: Range| -> Result<(), UnmapError> { + for addr in range.step_by(Size4KiB::SIZE as usize) { + let page: Page = Page::containing_address(addr); + match offset_table.unmap(page) { + Ok((_, flusher)) => flusher.flush(), + Err(UnmapError::PageNotMapped) => {} + Err(e) => return Err(e), + } } + + Ok(()) }; if end <= self.start_addr || start >= self.end_addr { @@ -585,16 +764,15 @@ impl Mapping { }); let new_mapping = Mapping { - protection: self.protection.clone(), - flags: self.flags.clone(), start_addr: end, end_addr: end + (self.end_addr - end), file: new_file, + refresh_flags: true, + flags: self.flags, }; - self.end_addr = end; - - Ok(UnmapResult::Parital(new_mapping)) + self.end_addr = start; + Ok(UnmapResult::Partial(new_mapping)) } else if start <= self.start_addr && end >= self.end_addr { // We are unmapping the whole region. unmap_range_inner(self.start_addr..self.end_addr)?; @@ -618,10 +796,38 @@ impl Mapping { // Update the end address of the mapping since we have unmapped the // last chunk of the mapping. - self.end_addr = end; + self.end_addr = start; Ok(UnmapResult::End) } } + + fn size(&self) -> usize { + (self.end_addr - self.start_addr) as usize + } + + fn split(&self, start: VirtAddr, end: VirtAddr) -> (Mapping, Mapping, Mapping) { + assert!(start > self.start_addr && end < self.end_addr); + + let mut left = self.clone(); + left.end_addr = start; + + let mut mid = self.clone(); + mid.start_addr = start; + mid.end_addr = end; + + let mut right = self.clone(); + right.start_addr = end; + + if self.file.is_some() { + left.file.as_mut().unwrap().size = left.size(); + mid.file.as_mut().unwrap().offset += left.size(); + mid.file.as_mut().unwrap().size = mid.size(); + right.file.as_mut().unwrap().offset += mid.size(); + right.file.as_mut().unwrap().size = right.size(); + } + + (left, mid, right) + } } struct VmProtected { @@ -635,30 +841,6 @@ impl VmProtected { } } - fn log(&self) { - for mmap in &self.mappings { - if let Some(file) = mmap.file.as_ref() { - log::debug!( - "{:?}..{:?} => {:?}, {:?} (offset={:#x}, size={:#x})", - mmap.start_addr, - mmap.end_addr, - mmap.protection, - mmap.flags, - file.offset, - file.size, - ); - } else { - log::debug!( - "{:?}..{:?} => {:?}, {:?}", - mmap.start_addr, - mmap.end_addr, - mmap.protection, - mmap.flags, - ); - } - } - } - fn handle_page_fault( &mut self, reason: PageFaultErrorCode, @@ -669,43 +851,36 @@ impl VmProtected { .iter_mut() .find(|e| accessed_address >= e.start_addr && accessed_address < e.end_addr) { - log::trace!("mapping {:?} on demand", accessed_address); - - if map.protection.is_empty() { + if map.protection().is_empty() { return false; } if reason.contains(PageFaultErrorCode::CAUSED_BY_WRITE) - && !map.protection.contains(MMapProt::PROT_WRITE) + && !map.flags.contains(VmFlag::WRITE) { return false; } if reason.contains(PageFaultErrorCode::INSTRUCTION_FETCH) - && !map.protection.contains(MMapProt::PROT_EXEC) + && !map.flags.contains(VmFlag::EXEC) { return false; } - let is_private = map.flags.contains(MMapFlags::MAP_PRIVATE); - let is_annon = map.flags.contains(MMapFlags::MAP_ANONYOMUS); - let mut address_space = AddressSpace::this(); let mut offset_table = address_space.offset_page_table(); - let result = match (is_private, is_annon) { + match (!map.flags.contains(VmFlag::SHARED), map.file.is_none()) { (true, true) => { map.handle_pf_private_anon(&mut offset_table, reason, accessed_address) } - (true, false) | (false, false) => { + (true | false, false) => { map.handle_pf_file(&mut offset_table, reason, accessed_address) } (false, true) => unreachable!("shared and anonymous mapping"), - }; - - result + } } else { log::trace!("mapping not found for address: {:#x}", accessed_address); self.log(); @@ -727,12 +902,10 @@ impl VmProtected { return None; } else if map.start_addr < address { cursor.move_next(); + } else if address + size > map.start_addr { + return None; } else { - if address + size > map.start_addr { - return None; - } else { - break; - } + break; } } @@ -748,7 +921,7 @@ impl VmProtected { return Some((address, self.mappings.cursor_front_mut())); } - let mut cursor = self.mappings.cursor_front_mut(); + let mut cursor = self.mappings.cursor_back_mut(); // Search the mappings starting at the current cursor position for a big // enough hole for where the address is above the provided `address`. A hole is @@ -759,27 +932,25 @@ impl VmProtected { if map.start_addr < address { cursor.move_next(); + } else if let Some(pmap) = cursor.peek_prev() { + let start = core::cmp::max(address, pmap.end_addr); + let hole = map_start.as_u64() - start.as_u64(); + + if hole as usize >= size { + return Some((start, cursor)); + } + + // The hole is too small + cursor.move_next(); } else { - if let Some(pmap) = cursor.peek_prev() { - let start = core::cmp::max(address, pmap.end_addr); - let hole = map_start.as_u64() - start.as_u64(); - - if hole as usize >= size { - return Some((start, cursor)); - } else { - // The hole is too small - cursor.move_next(); - } + let hole = map_start.as_u64() - address.as_u64(); + + return if hole as usize >= size { + Some((address, cursor)) } else { - let hole = map_start.as_u64() - address.as_u64(); - - return if hole as usize >= size { - Some((address, cursor)) - } else { - // The hole is too small - None - }; - } + // The hole is too small + None + }; } } @@ -790,116 +961,159 @@ impl VmProtected { &mut self, address: VirtAddr, size: usize, - protection: MMapProt, flags: MMapFlags, offset: usize, file: Option, + vm_flags: VmFlag, ) -> Option { + let z = file.clone(); + // Offset is required to be a multiple of page size. - if (offset as u64 & Size4KiB::SIZE - 1) != 0 { + if (offset as u64 & (Size4KiB::SIZE - 1)) != 0 { + log::warn!("mmap: offset is not a multiple of page size"); return None; } // The provided size should be non-zero. if size == 0 { + log::warn!("mmap: size is zero"); return None; } if file.is_some() { - // SAFTEY: We cannot mmap a file with the anonymous flag. if flags.contains(MMapFlags::MAP_ANONYOMUS) { + log::warn!("mmap: cannot map a file with the anonymous flag"); return None; } } else { - // SAFTEY: Mappings not backed by a file must be anonymous. if !flags.contains(MMapFlags::MAP_ANONYOMUS) { + log::warn!("mmap: mappings not backed by a file cannot be anonymous"); return None; } - // SAFTEY: We cannot have a shared and an anonymous mapping. if flags.contains(MMapFlags::MAP_SHARED) { + log::warn!("mmap: anonymous mappings cannot be shared"); return None; } } + // TODO: align_up may overflow. return if size_aligned == 0 let size_aligned = align_up(size as _, Size4KiB::SIZE); - if address == VirtAddr::zero() { + let x = if address == VirtAddr::zero() { // We need to find a free mapping above 0x7000_0000_0000. self.find_any_above(VirtAddr::new(0x7000_0000_0000), size_aligned as _) - } else { - if flags.contains(MMapFlags::MAP_FIXED) { - // SAFTEY: The provided address should be page aligned. - if !address.is_aligned(Size4KiB::SIZE) { - return None; - } - - // SAFTEY: The provided (address + size) should be less then - // the userland max address. - if (address + size_aligned) > userland_last_address() { - return None; - } + } else if flags.contains(MMapFlags::MAP_FIXED) { + if !address.is_aligned(Size4KiB::SIZE) { + log::warn!("mmap: fixed mapping address is not page aligned"); + return None; + } - self.munmap(address, size_aligned as usize); // Unmap any existing mappings. - self.find_fixed_mapping(address, size_aligned as _) - } else { - self.find_any_above(address, size) + if (address + size_aligned) > userland_last_address() { + log::warn!("mmap: fixed mapping address is out of range"); + return None; } + + self.munmap(address, size_aligned as usize); // Unmap any existing mappings. + self.find_fixed_mapping(address, size_aligned as _) + } else { + self.find_any_above(address, size) } - .and_then(|(addr, mut cursor)| { + .map(|(addr, mut cursor)| { // Merge same mappings instead of creating a new one. if let Some(prev) = cursor.peek_prev() { if prev.end_addr == addr - && prev.flags == flags - && prev.protection == protection + && prev.flags == vm_flags && prev.file.is_none() + && file.is_none() { prev.end_addr = addr + size_aligned; - - return Some(addr); + return addr; } } cursor.insert_before(Mapping { - protection, - flags, - start_addr: addr, end_addr: addr + size_aligned, file: file.map(|f| MMapFile::new(f, offset, size)), + refresh_flags: true, + flags: vm_flags, }); - Some(addr) - }) + addr + }); + + if x.is_none() { + log::warn!("mmap failed"); + self.log(); + + dbg!( + address, + size, + vm_flags, + flags, + offset, + z.map(|f| f.absolute_path()) + ); + + crate::unwind::unwind_stack_trace(); + } + + x + } + + fn log(&self) { + for mmap in &self.mappings { + if let Some(file) = mmap.file.as_ref() { + log::debug!( + "{:?}..{:?} => {:?} (offset={:#x}, size={:#x})", + mmap.start_addr, + mmap.end_addr, + mmap.flags, + file.offset, + file.size, + ); + } else { + log::debug!( + "{:?}..{:?} => {:?}", + mmap.start_addr, + mmap.end_addr, + mmap.flags, + ); + } + } } fn load_bin<'header>( &mut self, - bin: DirCacheItem, + bin: &DirCacheItem, argv: Option, envv: Option, ) -> Result, ElfLoadError> { // check for a shebang before proceeding. - if let Some(shebang) = parse_shebang(bin.clone())? { + if let Some(shebang) = parse_shebang(bin)? { log::debug!( "shebang: (interpreter={}, argument={})", - shebang.interpreter.absolute_path_str(), + shebang.interpreter.absolute_path(), shebang.argument ); let mut largv = ExecArgs::default(); - largv.push(shebang.interpreter.absolute_path_str().as_bytes()); + largv.push(shebang.interpreter.absolute_path().as_bytes()); if !shebang.argument.is_empty() { largv.push(shebang.argument.as_bytes()); } - largv.push(bin.absolute_path_str().as_bytes()); - argv.map(|argv| largv.extend(&argv.inner[1..])); + largv.push(bin.absolute_path().as_bytes()); + + if let Some(argv) = argv { + largv.extend(&argv.inner[1..]) + } - return self.load_bin(shebang.interpreter, Some(largv), envv); + return self.load_bin(&shebang.interpreter, Some(largv), envv); } let elf = Elf::new(bin.clone())?; @@ -907,7 +1121,7 @@ impl VmProtected { let load_offset = VirtAddr::new( if header.pt2.type_().as_type() == header::Type::SharedObject { - 0x40000000u64 + 0x4000_0000_u64 } else { 0u64 }, @@ -947,53 +1161,52 @@ impl VmProtected { let file_offset = align_down(header.offset(), Size4KiB::SIZE); - let mut prot = MMapProt::empty(); + let mut flags = VmFlag::MAY_READ | VmFlag::MAY_WRITE | VmFlag::MAY_EXEC; if header_flags.is_read() { - prot.insert(MMapProt::PROT_READ); + flags.insert(VmFlag::READ); } if header_flags.is_write() { - prot.insert(MMapProt::PROT_WRITE); + flags.insert(VmFlag::WRITE); } if header_flags.is_execute() { - prot.insert(MMapProt::PROT_EXEC); + flags.insert(VmFlag::EXEC); } - /* - * The last non-bss frame of the segment consists partly of data and partly of bss - * memory, which must be zeroed. Unfortunately, the file representation might have - * reused the part of the frame that should be zeroed to store the next segment. This - * means that we can't simply overwrite that part with zeroes, as we might overwrite - * other data this way. - * - * Example: - * - * XXXXXXXXXXXXXXX000000YYYYYYY000ZZZZZZZZZZZ virtual memory (XYZ are data) - * |·············| /·····/ /·········/ - * |·············| ___/·····/ /·········/ - * |·············|/·····/‾‾‾ /·········/ - * |·············||·····|/·̅·̅·̅·̅·̅·····/‾‾‾‾ - * XXXXXXXXXXXXXXXYYYYYYYZZZZZZZZZZZ file memory (zeros are not saved) - * ' ' ' ' ' - * The areas filled with dots (`·`) indicate a mapping between virtual and file - * memory. We see that the data regions `X`, `Y`, `Z` have a valid mapping, while - * the regions that are initialized with 0 have not. - * - * The ticks (`'`) below the file memory line indicate the start of a new frame. We - * see that the last frames of the `X` and `Y` regions in the file are followed - * by the bytes of the next region. So we can't zero these parts of the frame - * because they are needed by other memory regions. - */ + #[rustfmt::skip] + // The last non-bss frame of the segment consists partly of data and partly of bss + // memory, which must be zeroed. Unfortunately, the file representation might have + // reused the part of the frame that should be zeroed to store the next segment. This + // means that we can't simply overwrite that part with zeroes, as we might overwrite + // other data this way. + // + // Example: + // + // XXXXXXXXXXXXXXX000000YYYYYYY000ZZZZZZZZZZZ virtual memory (XYZ are data) + // |·············| /·····/ /·········/ + // |·············| ___/·····/ /·········/ + // |·············|/·····/‾‾‾ /·········/ + // |·············||·····|/·̅·̅·̅·̅·̅·····/‾‾‾‾ + // XXXXXXXXXXXXXXXYYYYYYYZZZZZZZZZZZ file memory (zeros are not saved) + // ' ' ' ' ' + // The areas filled with dots (`·`) indicate a mapping between virtual and file + // memory. We see that the data regions `X`, `Y`, `Z` have a valid mapping, while + // the regions that are initialized with 0 have not. + // + // The ticks (`'`) below the file memory line indicate the start of a new frame. We + // see that the last frames of the `X` and `Y` regions in the file are followed + // by the bytes of the next region. So we can't zero these parts of the frame + // because they are needed by other memory regions. let address = self .mmap( virtual_start, data_size as usize, - prot, MMapFlags::MAP_PRIVATE | MMapFlags::MAP_FIXED, file_offset as usize, Some(bin.clone()), + flags ) .ok_or(ElfLoadError::MemoryMapError)?; @@ -1005,10 +1218,10 @@ impl VmProtected { self.mmap( virtual_fend, bss_size as usize, - prot, MMapFlags::MAP_PRIVATE | MMapFlags::MAP_ANONYOMUS | MMapFlags::MAP_FIXED, 0, None, + flags, ) .ok_or(ElfLoadError::MemoryMapError)?; } @@ -1016,7 +1229,7 @@ impl VmProtected { } else if header_type == xmas_elf::program::Type::Interp { let ld = fs::lookup_path(fs::Path::new("/usr/lib/ld.so")).unwrap(); - let res = self.load_bin(ld, None, None)?; + let res = self.load_bin(&ld, None, None)?; entry_point = res.entry_point; } } @@ -1048,8 +1261,6 @@ impl VmProtected { let mut address_space = AddressSpace::this(); let mut offset_table = address_space.offset_page_table(); - log::debug!("unmapping {:?}..{:?}", start, end); - while let Some(map) = cursor.current() { if map.end_addr <= start { cursor.move_next(); @@ -1064,7 +1275,7 @@ impl VmProtected { cursor.remove_current(); } - UnmapResult::Parital(mapping) => { + UnmapResult::Partial(mapping) => { cursor.insert_after(mapping); return true; } @@ -1083,23 +1294,94 @@ impl VmProtected { success } - fn fork_from(&mut self, parent: &Vm) { - let data = parent.inner.lock_irq(); + fn mprotect( + &mut self, + addr: VirtAddr, + size: usize, + prot: MMapProt, + ) -> aero_syscall::Result<()> { + let start = addr.align_up(Size4KiB::SIZE); + let end = (addr + size).align_up(Size4KiB::SIZE); + + let mut cursor = self.mappings.cursor_front_mut(); + + while let Some(map) = cursor.current() { + if map.end_addr <= start { + cursor.move_next(); + } else if end <= map.start_addr || start >= map.end_addr { + break; + } else if start > map.start_addr && end < map.end_addr { + // The address we want to unmap is in the middle of the region. So we + // will need to split the mapping and update the end address accordingly. + let (left, mut mid, right) = map.split(start, end); + mid.set_protection(prot)?; + + cursor.insert_after(right); + cursor.insert_after(mid); + cursor.insert_after(left); + cursor.remove_current(); + break; + } else if start <= map.start_addr && end >= map.end_addr { + // full + map.set_protection(prot)?; + cursor.move_next(); + } else if start <= map.start_addr && end < map.end_addr { + // start + let mut mapping = map.clone(); + mapping.end_addr = end; + mapping.set_protection(prot)?; + + map.start_addr = end; + cursor.insert_before(mapping); + break; + } else { + // end + let mut mapping = map.clone(); + mapping.start_addr = start; + mapping.set_protection(prot)?; + + map.end_addr = start; + cursor.insert_after(mapping); + cursor.move_next(); + } + } + + Ok(()) + } + + #[must_use] + fn fork_from(&mut self, parent: &Vm) -> AddressSpace { + { + let parent = parent.inner.lock(); + self.mappings.clone_from(&parent.mappings); + } + + let mut address_space = AddressSpace::new().unwrap(); + let mut offset_table = address_space.offset_page_table(); + + let mut current = AddressSpace::this(); + let mut current = current.offset_page_table(); - // Copy over all of the mappings from the parent into the child. - self.mappings = data.mappings.clone(); + for map in self.mappings.iter().filter(|map| { + // Do not copy page table entries where a page fault can map them correctly. + !map.flags.contains(VmFlag::SHARED) && map.flags.contains(VmFlag::MAY_WRITE) + }) { + offset_table.copy_page_range(&mut current, map.start_addr..=map.end_addr); + } + + address_space } } pub struct Vm { - inner: Mutex, + inner: BMutex, } impl Vm { /// Creates a new instance of VM. pub(super) fn new() -> Self { Self { - inner: Mutex::new(VmProtected::new()), + inner: BMutex::new(VmProtected::new()), } } @@ -1110,37 +1392,86 @@ impl Vm { protection: MMapProt, flags: MMapFlags, offset: usize, - file: Option, + file: Option>, ) -> Option { + let mut vm_flags = + VmFlag::from(protection) | VmFlag::MAY_READ | VmFlag::MAY_WRITE | VmFlag::MAY_EXEC; + + let map_type = flags & (MMapFlags::MAP_SHARED | MMapFlags::MAP_PRIVATE); + + match (map_type, file.as_ref()) { + (MMapFlags::MAP_SHARED, Some(file)) => { + vm_flags.insert(VmFlag::SHARED); + + if !file.is_writable() { + if protection.contains(MMapProt::PROT_WRITE) { + return None; // EACCES + } + + // The mapping is going to be read-only forever so, it can be converted into a + // private mapping. + vm_flags.remove(VmFlag::MAY_WRITE | VmFlag::SHARED); + } + + if !file.is_readable() { + return None; // EACCES + } + + // TODO: * check if the filsystem is noexec mounted and remove the MAY_EXEC flag. + // * error out if prot contains PROT_EXEC & filesystem is noexec. + } + + (MMapFlags::MAP_PRIVATE, Some(file)) => { + if !file.is_readable() { + return None; // EACCES + } + + // TODO: * check if the filsystem is noexec mounted and remove the MAY_EXEC flag. + // * error out if prot contains PROT_EXEC & filesystem is noexec. + } + + (MMapFlags::MAP_SHARED, None) => vm_flags.insert(VmFlag::SHARED), + _ => {} + } + + let file = file.map(|file| file.dirnode()); self.inner - .lock_irq() - .mmap(address, size, protection, flags, offset, file) + .lock() + .mmap(address, size, flags, offset, file, vm_flags) } pub fn munmap(&self, address: VirtAddr, size: usize) -> bool { - self.inner.lock_irq().munmap(address, size) + self.inner.lock().munmap(address, size) } - pub(super) fn fork_from(&self, parent: &Vm) { - self.inner.lock_irq().fork_from(parent) + pub fn mprotect(&self, ptr: VirtAddr, size: usize, prot: MMapProt) { + self.inner.lock().mprotect(ptr, size, prot).unwrap() + } + + pub(super) fn fork_from(&self, parent: &Vm) -> AddressSpace { + self.inner.lock().fork_from(parent) + } + + pub fn log(&self) { + self.inner.lock().log() } /// Mapping the provided `bin` file into the VM. pub fn load_bin( &self, - bin: DirCacheItem, + bin: &DirCacheItem, argv: Option, envv: Option, ) -> Result { - self.inner.lock_irq().load_bin(bin, argv, envv) + self.inner.lock().load_bin(bin, argv, envv) } /// Clears and unmaps all of the mappings in the VM. pub(super) fn clear(&self) { - self.inner.lock_irq().clear() + self.inner.lock().clear() } - /// This function is responsible for handling page faults occured in + /// This function is responsible for handling page faults occurred in /// user mode. It determines the address, the reason of the page fault /// and then passes it off to one of the appropriate page fault handlers. pub(crate) fn handle_page_fault( @@ -1149,11 +1480,16 @@ impl Vm { accessed_address: VirtAddr, ) -> bool { self.inner - .lock_irq() + .lock() .handle_page_fault(reason, accessed_address) } - pub(crate) fn log(&self) { - self.inner.lock_irq().log() + pub fn for_each_mapping(&self, mut f: F) + where + F: FnMut(&Mapping), + { + for map in &self.inner.lock().mappings { + f(map); + } } } diff --git a/src/aero_kernel/src/utils/bitmap.rs b/src/aero_kernel/src/utils/bitmap.rs index b5e2a9089a1..747112639f4 100644 --- a/src/aero_kernel/src/utils/bitmap.rs +++ b/src/aero_kernel/src/utils/bitmap.rs @@ -1,3 +1,20 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + use core::alloc::Allocator; use alloc::vec::Vec; @@ -20,7 +37,7 @@ pub struct Bitmap { impl Bitmap { /// Constructs a new bitmap with `size` bits and uses `alloc` - /// as the alloctor. + /// as the allocator. /// /// ## Example /// ```rust @@ -43,7 +60,7 @@ impl Bitmap { /// ```rust /// let bitmap = Bitmap::new(); /// ``` - pub fn empty(alloc: A) -> Self { + pub const fn empty(alloc: A) -> Self { Self { bitmap: Vec::new_in(alloc), } @@ -98,22 +115,10 @@ impl Bitmap { /// ``` pub fn find_first_unset(&self) -> Option { for (i, block) in self.bitmap.iter().enumerate() { - let mut block_value = *block; - - if block_value == 0 { - return Some(i * BLOCK_BITS); + let trailing_ones = block.trailing_ones(); + if trailing_ones < BLOCK_BITS as u32 { + return Some(i * BLOCK_BITS + trailing_ones as usize); } - - let mut bit = 0; - - // Loop through the bits in the block and find - // the first unset bit. - while block_value.get_bit(0) { - block_value >>= 1; - bit += 1; - } - - return Some((i * BLOCK_BITS) + bit); } None @@ -132,19 +137,9 @@ impl Bitmap { /// ``` pub fn find_first_set(&self) -> Option { for (i, block) in self.bitmap.iter().enumerate() { - let mut block_value = *block; - - if block_value != 0 { - let mut bit = 0; - - // Loop through the bits in the block and find - // the first set bit. - while !block_value.get_bit(0) { - block_value >>= 1; - bit += 1; - } - - return Some((i * BLOCK_BITS) + bit); + let trailing_zeros = block.trailing_zeros(); + if trailing_zeros < BLOCK_BITS as u32 { + return Some(i * BLOCK_BITS + trailing_zeros as usize); } } @@ -157,33 +152,80 @@ mod test { use super::*; use alloc::alloc::Global; + const TEST_BITMAP_SIZE: usize = 4096; + #[test] - fn bitmap_first_unset_idx() { - let mut bitmap = Bitmap::new_in(Global, 4096); + fn find_first_unset() { + let mut map = Bitmap::new_in(Global, TEST_BITMAP_SIZE); - bitmap.set(69, true); - assert_eq!(bitmap.find_first_unset(), Some(0)); + // Set all of the bits to true. + for i in 0..TEST_BITMAP_SIZE { + assert_eq!(map.find_first_unset(), Some(i)); + map.set(i, true); + } - bitmap.set(0, true); - assert_eq!(bitmap.find_first_unset(), Some(1)); - } + assert_eq!(map.find_first_unset(), None); - #[test] - fn bitmap_first_set_idx() { - let mut bitmap = Bitmap::new_in(Global, 4096); + map.set(0, false); + assert_eq!(map.find_first_unset(), Some(0)); + + map.set(0, true); + map.set(1, false); + assert_eq!(map.find_first_unset(), Some(1)); - bitmap.set(69, true); - assert_eq!(bitmap.find_first_set(), Some(69)); + map.set(56, false); + assert_eq!(map.find_first_unset(), Some(1)); + + map.set(1, true); + assert_eq!(map.find_first_unset(), Some(56)); + + map.set(80, false); + assert_eq!(map.find_first_unset(), Some(56)); + + map.set(56, true); + assert_eq!(map.find_first_unset(), Some(80)); + + map.set(82, false); + assert_eq!(map.find_first_unset(), Some(80)); + + map.set(80, true); + assert_eq!(map.find_first_unset(), Some(82)); + + map.set(5, false); + assert_eq!(map.find_first_unset(), Some(5)); } #[test] - fn bitmap_set_and_test() { - let mut bitmap = Bitmap::new_in(Global, 4096); + fn find_first_set() { + let mut map = Bitmap::new_in(Global, TEST_BITMAP_SIZE); + assert_eq!(map.find_first_set(), None); + + map.set(0, true); + assert_eq!(map.find_first_set(), Some(0)); + + map.set(0, false); + map.set(1, true); + assert_eq!(map.find_first_set(), Some(1)); + + map.set(56, true); + assert_eq!(map.find_first_set(), Some(1)); + + map.set(1, false); + assert_eq!(map.find_first_set(), Some(56)); + + map.set(80, true); + assert_eq!(map.find_first_set(), Some(56)); + + map.set(56, false); + assert_eq!(map.find_first_set(), Some(80)); + + map.set(82, true); + assert_eq!(map.find_first_set(), Some(80)); - bitmap.set(69, true); - assert!(bitmap.is_set(69)); + map.set(80, false); + assert_eq!(map.find_first_set(), Some(82)); - bitmap.set(69, false); - assert!(!bitmap.is_set(69)); + map.set(5, true); + assert_eq!(map.find_first_set(), Some(5)); } } diff --git a/src/aero_kernel/src/utils/buffer.rs b/src/aero_kernel/src/utils/buffer.rs index 695f8aecc25..01bb8b87b1a 100644 --- a/src/aero_kernel/src/utils/buffer.rs +++ b/src/aero_kernel/src/utils/buffer.rs @@ -1,28 +1,26 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::fmt::Write; use alloc::vec::Vec; pub struct Buffer { - data: Vec, + pub data: Vec, } impl Buffer { @@ -118,13 +116,13 @@ impl + AsMut<[u8]>> RingBuffer { } } - return ""; + "" } /// Appends the provided byte to the ring buffer. pub fn append_byte(&mut self, byte: u8) { self.storage.as_mut()[self.position] = byte; - self.position = (self.position + 1) % self.storage.as_mut().len() + self.position = (self.position + 1) % self.storage.as_mut().len(); } } @@ -146,8 +144,8 @@ mod tests { fn partially_overwritten_buffer() { let mut buf = RingBuffer::new([0u8; 16]); write!(buf, "\nfirst\n").unwrap(); - write!(buf, "second\n").unwrap(); - write!(buf, "third\n").unwrap(); + writeln!(buf, "second").unwrap(); + writeln!(buf, "third").unwrap(); assert_eq!(buf.extract(), "st\nsecond\nthird\n"); } diff --git a/src/aero_kernel/src/drivers/block/nvme/dma.rs b/src/aero_kernel/src/utils/dma.rs similarity index 53% rename from src/aero_kernel/src/drivers/block/nvme/dma.rs rename to src/aero_kernel/src/utils/dma.rs index 11174bfab7b..15a26587bd1 100644 --- a/src/aero_kernel/src/drivers/block/nvme/dma.rs +++ b/src/aero_kernel/src/utils/dma.rs @@ -1,55 +1,52 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use alloc::boxed::Box; use core::alloc::{AllocError, Allocator, Layout}; use core::mem::MaybeUninit; -use core::ptr::NonNull; +use core::ptr::{self, NonNull}; use crate::mem::paging::*; pub struct DmaAllocator; -/* - * XXX: The main issue with DMA buffers is when they are bigger than one page. DMA buffers - * must be made of contiguous pages in physical memory because the device transfers the - * the data using the ISA or PCI system bus (which carry physical addresses). - */ +// XXX: The main issue with DMA buffers is when they are bigger than one page. DMA buffers +// must be made of contiguous pages in physical memory because the device transfers the +// the data using the ISA or PCI system bus (which carry physical addresses). unsafe impl Allocator for DmaAllocator { fn allocate(&self, layout: Layout) -> Result, AllocError> { - // XXX: The DMA buffer must be aligned to a page boundary. - let size = align_up(layout.size() as u64, Size2MiB::SIZE); + let size_bytes = layout.size(); - let pages = size / Size2MiB::SIZE; - assert!(pages == 1); - - let frame: PhysFrame = FRAME_ALLOCATOR.allocate_frame().ok_or(AllocError)?; - let virt = frame.start_address().as_hhdm_virt(); + let phys = FRAME_ALLOCATOR.alloc(size_bytes).ok_or(AllocError)?; + let virt = phys.as_hhdm_virt(); // SAFETY: The frame is aligned and non-null. - let ptr = unsafe { NonNull::new_unchecked(virt.as_mut_ptr() as *mut u8) }; - Ok(NonNull::slice_from_raw_parts(ptr, size as _)) + let ptr = unsafe { NonNull::new_unchecked(virt.as_mut_ptr()) }; + Ok(NonNull::slice_from_raw_parts(ptr, size_bytes)) } - unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) { - log::warn!("DMA memory deallocation is not *yet* implemented :) Enjoy the leaks :)") + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let size_bytes = layout.size(); + + let addr: usize = ptr.addr().into(); + let addr = VirtAddr::new(addr as u64); + + FRAME_ALLOCATOR.dealloc(addr.as_hhdm_phys(), size_bytes); } } @@ -66,7 +63,7 @@ impl Dma { /// ```rust,no_run /// let dma: Command = Dma::new(); /// ``` - pub fn new() -> Self { + pub fn zeroed() -> Self { let mut buffer = DmaBuffer::new_uninit_in(DmaAllocator); // SAFETY: Box returns a non-null and aligned pointer. @@ -81,6 +78,10 @@ impl Dma { pub fn new_uninit_slice(len: usize) -> Dma<[MaybeUninit]> { Dma(DmaBuffer::new_uninit_slice_in(len, DmaAllocator)) } + + pub fn new_zeroed_slice(len: usize) -> Dma<[MaybeUninit]> { + Dma(DmaBuffer::new_zeroed_slice_in(len, DmaAllocator)) + } } impl Dma<[MaybeUninit]> { @@ -108,10 +109,16 @@ impl core::ops::DerefMut for Dma { } } +impl core::fmt::Debug for Dma { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Dma").field(&self.0).finish() + } +} + impl Dma { pub fn addr(&self) -> PhysAddr { unsafe { - let phys = (&*self.0 as *const T as *const u8) as u64; + let phys = ptr::addr_of!(*self.0).addr() as u64; PhysAddr::new(phys - crate::PHYSICAL_MEMORY_OFFSET.as_u64()) } } diff --git a/src/aero_kernel/src/utils/linker.rs b/src/aero_kernel/src/utils/linker.rs deleted file mode 100644 index 7c97f98e5e5..00000000000 --- a/src/aero_kernel/src/utils/linker.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -extern "C" { - pub type LinkerSymbol; -} - -impl LinkerSymbol { - #[inline] - pub fn as_ptr(&'static self) -> *const u8 { - self as *const Self as *const u8 - } - - #[inline] - pub fn as_usize(&'static self) -> usize { - self.as_ptr() as usize - } -} - -unsafe impl Sync for LinkerSymbol {} -unsafe impl Send for LinkerSymbol {} diff --git a/src/aero_kernel/src/utils/mod.rs b/src/aero_kernel/src/utils/mod.rs index f8d1679ce93..029d1457ee5 100644 --- a/src/aero_kernel/src/utils/mod.rs +++ b/src/aero_kernel/src/utils/mod.rs @@ -1,26 +1,30 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use alloc::{alloc::alloc_zeroed, sync::Arc}; -use core::{alloc::Layout, any::Any, cell::UnsafeCell, mem, ptr::Unique}; - -use crate::mem::paging::{align_down, VirtAddr}; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use alloc::alloc::alloc_zeroed; +use alloc::sync::Arc; +use core::alloc::Layout; +use core::any::Any; +use core::cell::UnsafeCell; +use core::marker::PhantomData; +use core::ptr::Unique; +use core::{mem, ptr}; + +use crate::mem::paging::{align_down, ReadErr, VirtAddr}; #[cfg(target_arch = "x86_64")] use crate::arch::apic::get_cpu_count; @@ -32,43 +36,45 @@ fn get_cpu_count() -> usize { pub mod bitmap; pub mod buffer; -pub mod linker; +pub mod dma; pub mod sync; -pub fn validate_mut_ptr(ptr: *mut T) -> Option<&'static mut T> { +pub fn validate_mut_ptr(ptr: *mut T) -> Result<&'static mut T, ReadErr> { VirtAddr::new(ptr as _).read_mut::() } -pub fn validate_ptr(ptr: *const T) -> Option<&'static T> { +pub fn validate_ptr(ptr: *const T) -> Result<&'static T, ReadErr> { // SAFETY: Safe to cast const pointer to mutable since the pointer is not - // mutated and the returned reference is immutable. + // mutated and the returned reference is immutable. validate_mut_ptr(ptr as *mut T).map(|e| &*e) } -pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Option<&'static mut [T]> { +pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T], ReadErr> { if len == 0 { - Some(&mut []) + Ok(&mut []) } else { let _ = validate_ptr(ptr)?; // ensure non-null and in-range let _ = validate_ptr(unsafe { ptr.add(len) })?; // ensure in-range // SAFETY: We have validated the pointer above. - Some(unsafe { core::slice::from_raw_parts_mut(ptr, len) }) + Ok(unsafe { core::slice::from_raw_parts_mut(ptr, len) }) } } -pub fn validate_slice(ptr: *const T, len: usize) -> Option<&'static [T]> { +pub fn validate_slice(ptr: *const T, len: usize) -> Result<&'static [T], ReadErr> { // SAFETY: Safe to cast const pointer to mutable since the pointer is not - // mutated and the returned reference is immutable. + // mutated and the returned reference is immutable. validate_slice_mut(ptr as *mut T, len).map(|e| &*e) } -pub fn validate_str(ptr: *const u8, len: usize) -> Option<&'static str> { +pub fn validate_str(ptr: *const u8, len: usize) -> Result<&'static str, ReadErr> { let slice = validate_slice(ptr, len)?; - core::str::from_utf8(slice).ok() + core::str::from_utf8(slice).map_err(|_| ReadErr::Null) } -pub fn validate_array_mut(ptr: *mut T) -> Option<&'static mut [T; COUNT]> { +pub fn validate_array_mut( + ptr: *mut T, +) -> Result<&'static mut [T; COUNT], ReadErr> { let slice = validate_slice_mut::(ptr, COUNT); // Convert the validated slice to an array. // @@ -127,7 +133,7 @@ impl PerCpu { let cpu_count = get_cpu_count(); let size = mem::size_of::() * cpu_count; - let raw = unsafe { alloc_zeroed(Layout::from_size_align_unchecked(size, 8)) as *mut T }; + let raw = unsafe { alloc_zeroed(Layout::from_size_align_unchecked(size, 8)).cast::() }; unsafe { for i in 0..cpu_count { @@ -142,23 +148,23 @@ impl PerCpu { #[inline] pub fn as_mut_ptr(&self) -> *mut T { - unsafe { (&mut *self.data.get()).as_mut() } + unsafe { (*self.data.get()).as_mut() } } #[inline] pub fn get(&self) -> &T { - unsafe { &*self.as_mut_ptr().offset(crate::arch::tls::get_cpuid() as _) } + unsafe { &*self.as_mut_ptr().offset(0) } } #[inline] pub fn get_mut(&self) -> &mut T { - unsafe { &mut *self.as_mut_ptr().offset(crate::arch::tls::get_cpuid() as _) } + unsafe { &mut *self.as_mut_ptr().offset(0) } } } pub fn slice_into_bytes(slice: &[T]) -> &[u8] { - let data = slice.as_ptr() as *const u8; - let size = slice.len() * core::mem::size_of::(); + let data = slice.as_ptr().cast::(); + let size = core::mem::size_of_val(slice); unsafe { core::slice::from_raw_parts(data, size) } } @@ -218,29 +224,41 @@ impl<'a> StackHelper<'a> { } } -pub trait CeilDiv { - fn ceil_div(self, d: Self) -> Self; -} - -macro_rules! ceil_div_impl { - ($($t:ty)*) => ($( - impl CeilDiv for $t { - fn ceil_div(self, d: $t) -> $t { - (self + d - 1) / d - } +#[macro_export] +macro_rules! extern_sym { + ($sym:ident) => {{ + extern "C" { + static $sym: ::core::ffi::c_void; } - )*) + + // The value is not accessed, we only take its address. The `addr_of!()` ensures + // that no intermediate references is created. + ::core::ptr::addr_of!($sym) + }}; } -ceil_div_impl!(u8 u16 u32 u64 usize u128); +#[repr(C)] +#[derive(Debug, Default)] +pub struct IncompleteArrayField(PhantomData, [T; 0]); -#[cfg(test)] -mod tests { - use super::*; +impl IncompleteArrayField { + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ptr::from_mut(self).cast::() + } - #[test] - fn unsigned_div_ceil() { - assert_eq!((8usize).ceil_div(3), 3); - assert_eq!((7usize).ceil_div(4), 2); + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + ptr::from_ref(self).cast::() + } + + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + core::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } + + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + core::slice::from_raw_parts(self.as_ptr(), len) } } diff --git a/src/aero_kernel/src/utils/sync.rs b/src/aero_kernel/src/utils/sync.rs index 01a5600a6e4..8254e338c9d 100644 --- a/src/aero_kernel/src/utils/sync.rs +++ b/src/aero_kernel/src/utils/sync.rs @@ -1,62 +1,182 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use aero_syscall::{OpenFlags, SyscallError}; use alloc::sync::Arc; use alloc::vec::Vec; use crate::arch::interrupts; +use crate::fs::FileSystemError; use crate::userland::scheduler; -use crate::userland::signals::SignalResult; +use crate::userland::signals::SignalError; use crate::userland::task::Task; -/// Used to manage and block threads that are waiting for a condition to be true. -pub struct BlockQueue { +bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] + pub struct WaitQueueFlags: u32 { + const DISABLE_IRQ = 1 << 1; + const NON_BLOCK = 1 << 2; + } +} + +impl WaitQueueFlags { + pub const fn is_nonblock(&self) -> bool { + self.contains(WaitQueueFlags::NON_BLOCK) + } +} + +impl From for WaitQueueFlags { + fn from(flags: OpenFlags) -> Self { + let mut result = WaitQueueFlags::empty(); + if flags.contains(OpenFlags::O_NONBLOCK) { + result.insert(WaitQueueFlags::NON_BLOCK); + } + result + } +} + +#[derive(Debug, Copy, Clone)] +pub enum WaitQueueError { + Interrupted, + WouldBlock, +} + +impl From for FileSystemError { + fn from(err: WaitQueueError) -> Self { + match err { + WaitQueueError::Interrupted => FileSystemError::Interrupted, + WaitQueueError::WouldBlock => FileSystemError::WouldBlock, + } + } +} + +impl From for SyscallError { + fn from(err: WaitQueueError) -> Self { + match err { + WaitQueueError::Interrupted => SyscallError::EINTR, + WaitQueueError::WouldBlock => SyscallError::EAGAIN, + } + } +} + +/// Queue of tasks waiting for an event to occur. +pub struct WaitQueue { queue: Mutex>>, } -impl BlockQueue { - /// Creates a new block queue. - #[inline] - pub fn new() -> Self { +impl WaitQueue { + /// Create a new wait queue. + pub const fn new() -> Self { Self { queue: Mutex::new(Vec::new()), } } - /// Run a future to completion on the current task. This function will block - /// the caller until the given future has completed. - pub fn block_on<'future, T, F: FnMut(&mut MutexGuard) -> bool>( + fn _wait<'a, T, F>( &self, - mutex: &'future Mutex, - mut future: F, - ) -> SignalResult> { - let mut lock = mutex.lock_irq(); + mutex: &'a Mutex, + mut cond: F, + interruptable: bool, + flags: WaitQueueFlags, + ) -> Result, WaitQueueError> + where + F: FnMut(&mut MutexGuard) -> bool, + { + let acquire = || { + if flags.contains(WaitQueueFlags::DISABLE_IRQ) { + mutex.lock() + } else { + mutex.lock_irq() + } + }; - // Check if the future was already completed. - if future(&mut lock) { + let mut lock = acquire(); + if cond(&mut lock) { + // Condition is already satisfied. return Ok(lock); } + if flags.is_nonblock() { + return Err(WaitQueueError::WouldBlock); + } + let scheduler = scheduler::get_scheduler(); - let task = scheduler.current_task(); + let task = scheduler::current_thread(); + + // If no IRQs was requested, the above lock would have disabled them so, + // `lock_irq` is not required here. + self.queue.lock().push(task.clone()); - self.queue.lock_irq().push(task.clone()); + while !cond(&mut lock) { + drop(lock); - // Wait until the future is completed. - while !future(&mut lock) { - core::mem::drop(lock); // Drop the IRQ lock and await for IO to complete. - scheduler.inner.await_io()?; + match scheduler.await_io() { + Ok(()) => lock = mutex.lock_irq(), + Err(SignalError::Interrupted) if !interruptable => lock = acquire(), - // Re-acquire the lock. - lock = mutex.lock_irq(); + Err(SignalError::Interrupted) => { + self.remove(&task); + return Err(WaitQueueError::Interrupted); + } + } } - self.remove(task); + self.remove(&task); Ok(lock) } + /// Sleeps until a condition is met. + /// + /// Should be used when waiting for events such as completion of disk I/O. Any signals sent + /// while waiting shall not be delivered until the condition is met and the wait is over. + pub fn wait_uninterruptible<'a, T, F>( + &self, + flags: WaitQueueFlags, + mutex: &'a Mutex, + cond: F, + ) -> MutexGuard<'a, T> + where + F: FnMut(&mut MutexGuard) -> bool, + { + unsafe { + self._wait(mutex, cond, false, flags) + // SAFETY: [`SignalError`] cannot occur on non-interruptible wait. + .unwrap_unchecked() + } + } + + /// Sleeps until a condition is met. + /// + /// Should be used when waiting for events such as data being written to a pipe. Returns + /// [`SignalError::Interrupted`] if the wait was interrupted by a signal. + pub fn wait<'a, T, F: FnMut(&mut MutexGuard) -> bool>( + &self, + flags: WaitQueueFlags, + mutex: &'a Mutex, + cond: F, + ) -> Result, WaitQueueError> { + self._wait(mutex, cond, true, flags) + } + pub fn insert(&self, task: Arc) { self.queue.lock_irq().push(task); } - pub fn remove(&self, task: Arc) { + pub fn remove(&self, task: &Task) { let mut tasks = self.queue.lock_irq(); tasks @@ -72,14 +192,23 @@ impl BlockQueue { .map(|i| tasks.remove(i)); } - /// Notify's all of the tasks in the blocker's queue that the future has been - /// completed. - pub fn notify_complete(&self) { + /// Wakes up all of the process in the wait queue. + pub fn notify_all(&self) { let scheduler = scheduler::get_scheduler(); let this = self.queue.lock_irq(); for task in this.iter() { - scheduler.inner.wake_up(task.clone()); + scheduler.wake_up(task.clone()); + } + } + + /// Wakes up only the first process in the wait queue. + pub fn notify(&self) { + let scheduler = scheduler::get_scheduler(); + let this: MutexGuard>> = self.queue.lock_irq(); + + if let Some(task) = this.first() { + scheduler.wake_up(task.clone()); } } @@ -88,6 +217,12 @@ impl BlockQueue { } } +impl Default for WaitQueue { + fn default() -> Self { + Self::new() + } +} + /// Helper guard structure used to lock interrupts. When dropped, interrupts /// are enabled again. This is useful for volatile operations where we don't /// want to be interrupted. @@ -118,8 +253,65 @@ impl Drop for IrqGuard { } } +/// A blocking-based lock providing mutually exclusive access to the data. +pub struct BMutex { + wq: WaitQueue, + spin: Mutex, +} + +impl BMutex { + pub const fn new(value: T) -> Self { + Self { + wq: WaitQueue::new(), + spin: Mutex::new(value), + } + } + + pub fn lock(&self) -> BMutexGuard { + let task = scheduler::get_scheduler().current_task(); + self.wq.insert(task.clone()); + + loop { + if let Some(guard) = self.spin.inner.try_lock() { + self.wq.remove(&task); + + return BMutexGuard { guard, mutex: self }; + } + + let _ = scheduler::get_scheduler().await_io(); + } + } +} + +pub struct BMutexGuard<'a, T: ?Sized + 'a> { + guard: spin::MutexGuard<'a, T>, + mutex: &'a BMutex, +} + +impl core::ops::Deref for BMutexGuard<'_, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + self.guard.deref() + } +} + +impl core::ops::DerefMut for BMutexGuard<'_, T> { + #[inline] + fn deref_mut(&mut self) -> &mut T { + self.guard.deref_mut() + } +} + +impl Drop for BMutexGuard<'_, T> { + fn drop(&mut self) { + self.mutex.wq.notify(); + } +} + /// A spin-based lock providing mutually exclusive access to data. -pub struct Mutex { +pub struct Mutex { inner: spin::Mutex, } @@ -147,8 +339,8 @@ impl Mutex { /// /// The returned value may be dereferenced for data access and the lock will be dropped and /// interrupts will be re-enabled when the guard falls out of scope. Deadlocks occur if a thread - /// tries to acquire a lock that will never become free. Thus, locking interrupts is useful for volatile - /// operations where we might be interrupted. + /// tries to acquire a lock that will never become free. Thus, locking interrupts is useful for + /// volatile operations where we might be interrupted. pub fn lock_irq(&self) -> MutexGuard { let irq_lock = interrupts::is_enabled(); @@ -179,23 +371,23 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { irq_lock: bool, } -impl<'a, T: ?Sized> core::ops::Deref for MutexGuard<'a, T> { +impl core::ops::Deref for MutexGuard<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { - self.guard.deref() + &self.guard } } -impl<'a, T: ?Sized> core::ops::DerefMut for MutexGuard<'a, T> { +impl core::ops::DerefMut for MutexGuard<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut T { - self.guard.deref_mut() + &mut self.guard } } -impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { +impl Drop for MutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { diff --git a/src/aero_proc/Cargo.toml b/src/aero_proc/Cargo.toml index feeee04f920..f13c4edc75c 100644 --- a/src/aero_proc/Cargo.toml +++ b/src/aero_proc/Cargo.toml @@ -12,9 +12,9 @@ default = [] proc-macro = true [dependencies] -proc-macro2 = "1.0.37" +proc-macro2 = "1.0.78" proc-macro-error = "1.0.4" -quote = "1.0.18" +quote = "1" [dependencies.syn] features = ["full"] diff --git a/src/aero_proc/src/cpu_local.rs b/src/aero_proc/src/cpu_local.rs new file mode 100644 index 00000000000..e287505f92f --- /dev/null +++ b/src/aero_proc/src/cpu_local.rs @@ -0,0 +1,58 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use proc_macro::TokenStream; +use syn::{Lit, Meta, MetaNameValue, NestedMeta}; + +pub fn parse(attr: TokenStream, item: TokenStream) -> TokenStream { + let item = syn::parse_macro_input!(item as syn::ItemStatic); + + let ty = &item.ty; + let ident = &item.ident; + let mutability = &item.mutability; + let vis = &item.vis; + let initializer = &item.expr; + + // Parse the attribute arguments + let args = syn::parse_macro_input!(attr as syn::AttributeArgs); + + // Process each argument to find the subsection value + let mut subsection = None; + for arg in args { + if let NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) = arg { + if let Some(ident) = path.get_ident() { + if ident == "subsection" { + if let Lit::Str(lit_str) = lit { + subsection = Some(lit_str.value()); + } + } + } + } + } + + let link_section = match subsection { + Some(subsection) => format!(".cpu_local_{}", subsection), + None => ".cpu_local".to_string(), + }; + + quote::quote! { + #[link_section = #link_section] + #[used] + #vis static #mutability #ident: crate::arch::cpu_local::CpuLocal<#ty> = crate::arch::cpu_local::CpuLocal::new(#initializer); + } + .into() +} diff --git a/src/aero_proc/src/downcastable.rs b/src/aero_proc/src/downcastable.rs index abe490bd032..8ffdf27de3d 100644 --- a/src/aero_proc/src/downcastable.rs +++ b/src/aero_proc/src/downcastable.rs @@ -1,3 +1,20 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + use proc_macro::TokenStream; use syn::spanned::Spanned; @@ -10,13 +27,11 @@ pub fn parse(_: TokenStream, item: TokenStream) -> TokenStream { let generics = &parsed_trait.generics; // `auto` and `unsafe` traits are not allowed: - parsed_trait - .auto_token - .map(|e| emit_error!(e.span(), "`auto` traits are not downcastable")); - - parsed_trait - .unsafety - .map(|e| emit_error!(e.span(), "`unsafe` traits are not downcastable")); + if let Some(token) = parsed_trait.auto_token { + emit_error!(token.span(), "`auto` traits are not downcastable") + } else if let Some(token) = parsed_trait.unsafety { + emit_error!(token.span(), "`unsafe` traits are not downcastable") + } let super_traits = parsed_trait.supertraits.clone(); diff --git a/src/aero_proc/src/indirect.rs b/src/aero_proc/src/indirect.rs new file mode 100644 index 00000000000..f4b4b1d6478 --- /dev/null +++ b/src/aero_proc/src/indirect.rs @@ -0,0 +1,76 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use proc_macro::TokenStream; +use proc_macro2::{Ident, Span}; +use syn::spanned::Spanned; + +pub fn parse(_: TokenStream, item: TokenStream) -> TokenStream { + let item = syn::parse_macro_input!(item as syn::ItemFn); + let args = item.sig.inputs; + + if !args.is_empty() { + abort!(args.span(), "resolver is expected to take no arguments"); + } + + let name = item.sig.ident.to_string(); + let vis = item.vis; + + let output_fn = match item.sig.output { + syn::ReturnType::Type(_, ty) => match ty.as_ref() { + syn::Type::BareFn(bare_fn) => bare_fn.clone(), + ty => abort!(ty.span(), "expected output function type"), + }, + ty => abort!(ty.span(), "expected output function type"), + }; + + let output_args = &output_fn.inputs; + let output_ret = &output_fn.output; + + // Underscores at the beginning of the identifier make it reserved, and the more underscores + // there are, the more reserveder it is. + let resolve_name = Ident::new(&format!("__resolve_{name}"), Span::call_site()); + + let inline = format!( + r" + .global {name} + + .type {name}, @gnu_indirect_function + .set {name},{{}} + " + ); + + let name = &item.sig.ident; + let resolve_body = &item.block; + + quote::quote! { + fn #resolve_name() -> usize { + let resolved_function = { + #resolve_body + }; + + resolved_function as usize + } + + ::core::arch::global_asm!(#inline, sym #resolve_name); + + extern "C" { + #vis fn #name(#output_args) #output_ret; + } + } + .into() +} diff --git a/src/aero_proc/src/ioctl.rs b/src/aero_proc/src/ioctl.rs new file mode 100644 index 00000000000..4867aec43b3 --- /dev/null +++ b/src/aero_proc/src/ioctl.rs @@ -0,0 +1,74 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use proc_macro::TokenStream; +use syn::{Data, DeriveInput, Path}; + +fn make_command_enum(ast: &DeriveInput) -> TokenStream { + let name = &ast.ident; + let variants = match &ast.data { + Data::Enum(data) => &data.variants, + _ => panic!("`Ioctl` derive macro can only be used on enums."), + }; + + let mut pattern_match = vec![]; + + for variant in variants { + let attrs = &variant.attrs; + let ident = &variant.ident; + + for attr in attrs { + if attr.path.get_ident().unwrap() != "command" { + assert_eq!(attr.path.get_ident().unwrap(), "doc"); + continue; + } + + let path = attr.parse_args::().unwrap(); + + pattern_match.push(match &variant.fields { + syn::Fields::Unit => quote::quote!(#path => Self::#ident), + syn::Fields::Unnamed(fields) => { + assert!(fields.unnamed.len() == 1); + quote::quote!(#path => Self::#ident(crate::syscall::SysArg::from_usize(arg))) + } + + _ => panic!("`Ioctl` derive macro can only be used on enums with unit variants."), + }); + } + } + + // implement Ioctl::from_command_arg for the enum + + quote::quote! { + impl #name { + pub fn from_command_arg(cmd: usize, arg: usize) -> Self { + match cmd { + #(#pattern_match,)* + _ => unimplemented!("unknown command: {cmd:#x}") + } + } + } + } + .into() +} + +pub fn parse(item: TokenStream) -> TokenStream { + let ast: DeriveInput = syn::parse(item).unwrap(); + let cmd_enum = make_command_enum(&ast); + + cmd_enum +} diff --git a/src/aero_proc/src/lib.rs b/src/aero_proc/src/lib.rs index b582f34c7c2..75cafa90d69 100644 --- a/src/aero_proc/src/lib.rs +++ b/src/aero_proc/src/lib.rs @@ -1,28 +1,29 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #![feature(proc_macro_diagnostic, proc_macro_span)] #[macro_use] extern crate proc_macro_error; +mod cpu_local; mod downcastable; +mod indirect; +mod ioctl; mod syscall; mod test; @@ -59,3 +60,21 @@ pub fn syscall(attr: TokenStream, item: TokenStream) -> TokenStream { pub fn downcastable(attr: TokenStream, item: TokenStream) -> TokenStream { downcastable::parse(attr, item) } + +#[proc_macro_attribute] +#[proc_macro_error] +pub fn cpu_local(attr: TokenStream, item: TokenStream) -> TokenStream { + cpu_local::parse(attr, item) +} + +#[proc_macro_attribute] +#[proc_macro_error] +pub fn indirect(attr: TokenStream, item: TokenStream) -> TokenStream { + indirect::parse(attr, item) +} + +#[proc_macro_derive(Ioctl, attributes(command))] +#[proc_macro_error] +pub fn ioctl(item: TokenStream) -> TokenStream { + ioctl::parse(item) +} diff --git a/src/aero_proc/src/syscall.rs b/src/aero_proc/src/syscall.rs index 12b9c2e88f8..0651e41e642 100644 --- a/src/aero_proc/src/syscall.rs +++ b/src/aero_proc/src/syscall.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use proc_macro::TokenStream; use proc_macro2::{Ident, Span}; @@ -72,17 +70,13 @@ pub fn parse(attr: TokenStream, item: TokenStream) -> TokenStream { let parsed_fn = syn::parse_macro_input!(item as syn::ItemFn); let signature = &parsed_fn.sig; - signature - .constness - .map(|e| emit_error!(e.span(), "syscall functions cannot be `const`")); - - signature - .asyncness - .map(|e| emit_error!(e.span(), "syscall functions cannot be `async`")); - - signature - .unsafety - .map(|e| emit_error!(e.span(), "syscalls functions cannot be `unsafe`")); + if let Some(token) = signature.constness { + emit_error!(token.span(), "syscall functions cannot be `const`"); + } else if let Some(token) = signature.asyncness { + emit_error!(token.span(), "syscall functions cannot be `async`"); + } else if let Some(token) = signature.unsafety { + emit_error!(token.span(), "syscall functions cannot be `unsafe`"); + } let generics = &signature.generics; @@ -105,6 +99,16 @@ pub fn parse(attr: TokenStream, item: TokenStream) -> TokenStream { let orig_args = &signature.inputs; let processed_args = process_args(orig_args); let call_args = process_call_args(orig_args); + let args = orig_args + .iter() + .map(|e| match e { + FnArg::Typed(arg) => match arg.pat.as_ref() { + Pat::Ident(pat) => pat.ident.clone(), + _ => unimplemented!(), + }, + _ => unimplemented!(), + }) + .collect::>(); let ret = &signature.output; let body = &parsed_fn.block; @@ -141,31 +145,43 @@ pub fn parse(attr: TokenStream, item: TokenStream) -> TokenStream { }) .collect::>(); - let syslog = quote::quote! { - #[cfg(feature = "syslog")] - crate::syscall::SysLog::new(stringify!(#name)) - #(#syslog_args)* - .set_result(result) - .flush(); - }; + let syslog = quote::quote! {{ + // Check if the current task has systrace enabled. + use crate::userland::scheduler; + + let current_task = scheduler::get_scheduler().current_task(); + if current_task.systrace() { + crate::syscall::SysLog::new(stringify!(#name)) + #(#syslog_args)* + .set_result(result) + .flush(); + } + }}; let compiled_body = if config.no_return { - quote::quote! { #body } + quote::quote! { + fn even_inner(#orig_args) #ret #body + even_inner(#(#call_args),*) + } } else { quote::quote! { - let result = #body; - #syslog - result + #[inline(always)] + fn even_inner(#orig_args) #ret #body + + #[inline(always)] + fn syscall_inner(#orig_args) #ret { + let result = even_inner(#(#args),*); + #syslog + result + } + + syscall_inner(#(#call_args),*) } }; let result = quote! { #(#attrs)* #vis fn #name(#(#processed_args),*) #ret { - #(#attrs)* fn inner_syscall(#orig_args) #ret { - #compiled_body - } - - inner_syscall(#(#call_args),*) + #compiled_body } }; @@ -218,12 +234,9 @@ fn process_args(args: &Punctuated) -> Vec { result.push(syn::parse_quote!(#data: usize)); } - Some(ArgType::Pointer(_)) | Some(ArgType::Reference(_)) => { + _ => { result.push(syn::parse_quote!(#(#attrs)* #ident: usize)); } - None => { - result.push(syn::parse_quote!(#(#attrs)* #ident: #typ)); - } }; } _ => { @@ -249,81 +262,68 @@ fn process_call_args(args: &Punctuated) -> Vec { let mut result = Vec::new(); for arg in args { - match arg { - FnArg::Typed(arg) => match arg.pat.as_ref() { - Pat::Ident(pat) => { - let ty = &arg.ty; - let ident = &pat.ident; + if let FnArg::Typed(arg) = arg { + if let Pat::Ident(pat) = arg.pat.as_ref() { + let ty = &arg.ty; + let ident = &pat.ident; + + if let Some(arg_type) = determine_arg_type(ty) { + let data_ident = Ident::new(&format!("{}_data", ident), Span::call_site()); + let len_ident = Ident::new(&format!("{}_len", ident), Span::call_site()); + + match arg_type { + ArgType::Slice(is_mut) => { + let slice_expr: Expr = if is_mut { + syn::parse_quote!(crate::utils::validate_slice_mut(#data_ident as *mut _, #len_ident)?) + } else { + syn::parse_quote!(crate::utils::validate_slice(#data_ident as *const _, #len_ident)?) + }; + + result.push(slice_expr); + } - if let Some(arg_type) = determine_arg_type(ty) { - let data_ident = Ident::new(&format!("{}_data", ident), Span::call_site()); - let len_ident = Ident::new(&format!("{}_len", ident), Span::call_site()); - - match arg_type { - ArgType::Slice(is_mut) => { - let slice_expr: Expr = if is_mut { - syn::parse_quote! { - crate::utils::validate_slice_mut(#data_ident as *mut _, #len_ident).ok_or(SyscallError::EINVAL)? - } - } else { - syn::parse_quote! { - crate::utils::validate_slice(#data_ident as *const _, #len_ident).ok_or(SyscallError::EINVAL)? - } - }; - - result.push(slice_expr); - } - ArgType::Array(is_mut) => { - let array_expr: Expr = if is_mut { - syn::parse_quote! { - crate::utils::validate_array_mut(#data_ident as *mut _).ok_or(SyscallError::EINVAL)? - } - } else { - unimplemented!() - }; - - result.push(array_expr); - } - ArgType::Pointer(is_mut) => { - let ptr_expr: Expr = if is_mut { - syn::parse_quote!(#ident as *mut _) - } else { - syn::parse_quote!(#ident as *const _) - }; - - result.push(ptr_expr); - } - ArgType::Reference(is_mut) => { - let ref_expr: Expr = if is_mut { - syn::parse_quote!({ - crate::utils::validate_mut_ptr(#ident as *mut _).ok_or(SyscallError::EINVAL)? - }) - } else { - syn::parse_quote!({ - crate::utils::validate_ptr(#ident as *const _).ok_or(SyscallError::EINVAL)? - }) - }; - - result.push(ref_expr); - } - ArgType::String => result.push(syn::parse_quote! { - crate::utils::validate_str(#data_ident as *const _, #len_ident).ok_or(SyscallError::EINVAL)? - }), - ArgType::Path => result.push(syn::parse_quote! { - { - let string = crate::utils::validate_str(#data_ident as *const _, #len_ident).ok_or(SyscallError::EINVAL)?; - let path = Path::new(string); - path - } - }), + ArgType::Array(is_mut) => { + let array_expr: Expr = if is_mut { + syn::parse_quote!(crate::utils::validate_array_mut(#data_ident as *mut _)?) + } else { + unimplemented!() + }; + + result.push(array_expr); + } + + ArgType::Pointer(is_mut) => { + let ptr_expr: Expr = if is_mut { + syn::parse_quote!(#ident as *mut _) + } else { + syn::parse_quote!(#ident as *const _) + }; + + result.push(ptr_expr); + } + + ArgType::Reference(is_mut) => { + let ref_expr: Expr = if is_mut { + syn::parse_quote!(crate::utils::validate_mut_ptr(#ident as *mut _)?) + } else { + syn::parse_quote!(crate::utils::validate_ptr(#ident as *const _)?) + }; + + result.push(ref_expr); + } + + ArgType::String => result.push(syn::parse_quote!(crate::utils::validate_str(#data_ident as *const _, #len_ident)?)), + ArgType::Path => { + result.push(syn::parse_quote!({ + let string = crate::utils::validate_str(#data_ident as *const _, #len_ident)?; + Path::new(string) + })) } - } else { - result.push(syn::parse_quote!(#ident)); } + } else { + result.push(syn::parse_quote!(crate::syscall::SysArg::from_usize(#ident))); } - _ => {} - }, - _ => {} + } } } diff --git a/src/aero_proc/src/test.rs b/src/aero_proc/src/test.rs index 27f191cb3bb..a009d741ab3 100644 --- a/src/aero_proc/src/test.rs +++ b/src/aero_proc/src/test.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use proc_macro::TokenStream; use syn::ItemFn; diff --git a/src/aero_syscall/Cargo.toml b/src/aero_syscall/Cargo.toml index a371ea5b74b..1aac85f20f0 100644 --- a/src/aero_syscall/Cargo.toml +++ b/src/aero_syscall/Cargo.toml @@ -6,3 +6,7 @@ edition = "2021" [dependencies] bitflags = "1.2.1" +num-derive = { version = "0.3", default-features = false } +num-traits = { version = "0.2", default-features = false } +byte_endian = { git = "https://github.com/aero-os/byte_endian" } +static_assertions = "1.1.0" diff --git a/src/aero_syscall/src/consts.rs b/src/aero_syscall/src/consts.rs index f3c4516d8b4..e3196cdb41c 100644 --- a/src/aero_syscall/src/consts.rs +++ b/src/aero_syscall/src/consts.rs @@ -1,21 +1,21 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +use core::ffi; use crate::OpenFlags; @@ -86,19 +86,59 @@ pub const SYS_EXIT_THREAD: usize = 62; pub const SYS_SOCK_RECV: usize = 63; pub const SYS_SETITIMER: usize = 64; pub const SYS_GETITIMER: usize = 65; +pub const SYS_GETPPID: usize = 66; +pub const SYS_SOCKET_PAIR: usize = 67; +pub const SYS_RENAME: usize = 68; +pub const SYS_MPROTECT: usize = 69; // haha funny number +pub const SYS_SOCK_SEND: usize = 70; +pub const SYS_TRACE: usize = 71; +pub const SYS_SETPGID: usize = 72; +pub const SYS_SETSID: usize = 73; +pub const SYS_GETPGID: usize = 74; +pub const SYS_SOCK_SHUTDOWN: usize = 75; +pub const SYS_GETPEERNAME: usize = 76; +pub const SYS_GETSOCKNAME: usize = 77; +pub const SYS_DEBUG: usize = 78; +pub const SYS_SETSOCKOPT: usize = 79; +pub const SYS_GETSOCKOPT: usize = 80; +pub const SYS_SYMLINK_AT: usize = 81; // constants for fcntl()'s command argument: -pub const F_DUPFD: usize = 1; -pub const F_DUPFD_CLOEXEC: usize = 2; -pub const F_GETFD: usize = 3; -pub const F_SETFD: usize = 4; -pub const F_GETFL: usize = 5; -pub const F_SETFL: usize = 6; -pub const F_GETLK: usize = 7; -pub const F_SETLK: usize = 8; -pub const F_SETLKW: usize = 9; -pub const F_GETOWN: usize = 10; -pub const F_SETOWN: usize = 11; +// mlibc/abis/linux/fcntl.h +pub const F_DUPFD: usize = 0; +pub const F_GETFD: usize = 1; +pub const F_SETFD: usize = 2; +pub const F_GETFL: usize = 3; +pub const F_SETFL: usize = 4; + +pub const F_SETOWN: usize = 8; +pub const F_GETOWN: usize = 9; +pub const F_SETSIG: usize = 10; +pub const F_GETSIG: usize = 11; + +pub const F_GETLK: usize = 5; +pub const F_SETLK: usize = 6; +pub const F_SETLKW: usize = 7; + +pub const F_SETOWN_EX: usize = 15; +pub const F_GETOWN_EX: usize = 16; + +pub const F_GETOWNER_UIDS: usize = 17; + +pub const F_DUPFD_CLOEXEC: usize = 1030; +pub const F_ADD_SEALS: usize = 1033; +pub const F_GET_SEALS: usize = 1034; + +pub const F_SEAL_SEAL: usize = 0x0001; +pub const F_SEAL_SHRINK: usize = 0x0002; +pub const F_SEAL_GROW: usize = 0x0004; +pub const F_SEAL_WRITE: usize = 0x0008; + +pub const F_RDLCK: usize = 0; +pub const F_WRLCK: usize = 1; +pub const F_UNLCK: usize = 2; + +pub const FD_CLOEXEC: usize = 1; // constants for fcntl()'s additional argument of F_GETFD and F_SETFD: bitflags::bitflags! { @@ -130,6 +170,7 @@ pub union EPollData { // options/linux/include/sys/epoll.h bitflags::bitflags! { + #[repr(transparent)] pub struct EPollEventFlags: u32 { const IN = 0x001; /// There is an exceptional condition on the file descriptor. @@ -151,7 +192,7 @@ bitflags::bitflags! { } #[derive(Copy, Clone)] -#[repr(C)] +#[cfg_attr(target_arch = "x86_64", repr(packed))] pub struct EPollEvent { pub events: EPollEventFlags, pub data: EPollData, @@ -159,8 +200,10 @@ pub struct EPollEvent { impl core::fmt::Debug for EPollEvent { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let events = self.events; + f.debug_struct("EPollEvent") - .field("events", &self.events) + .field("events", &events) .finish() } } @@ -214,6 +257,8 @@ bitflags::bitflags! { pub const FBIOGET_VSCREENINFO: usize = 0x4600; pub const FBIOPUT_VSCREENINFO: usize = 0x4601; pub const FBIOGET_FSCREENINFO: usize = 0x4602; +pub const FBIOGETCMAP: usize = 0x4604; +pub const FBIOPUTCMAP: usize = 0x4605; pub const FB_TYPE_PACKED_PIXELS: u32 = 0; pub const FB_TYPE_PLANES: u32 = 1; @@ -259,6 +304,31 @@ impl FramebufferBitField { } } +// device independent colour information: +#[derive(Debug)] +#[repr(C)] +pub struct FramebufferCmap { + pub start: u32, // first entry + pub len: u32, // number of entries + pub red: *mut u16, + pub green: *mut u16, + pub blue: *mut u16, + pub transp: *mut u16, // can be NULL +} + +impl Default for FramebufferCmap { + fn default() -> Self { + Self { + start: Default::default(), + len: Default::default(), + red: core::ptr::null_mut(), + green: core::ptr::null_mut(), + blue: core::ptr::null_mut(), + transp: core::ptr::null_mut(), + } + } +} + // framebuffer variable screen info: #[derive(Default, Debug, Clone)] #[repr(C)] @@ -314,3 +384,47 @@ pub struct FramebufferFScreenInfo { pub capabilities: u16, pub reserved: [u16; 2], } + +// networking ioctls: +pub const SIOCGIFINDEX: usize = 0x8933; +pub const SIOCGIFHWADDR: usize = 0x8927; +pub const SIOCSIFADDR: usize = 0x8916; // set PA address +pub const SIOCSIFNETMASK: usize = 0x891c; // set network PA mask + +const IF_NAME_SIZE: usize = 16; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct SockAddrStorage { + pub sa_family: u32, + pub sa_data: [u8; 14], +} + +#[repr(C)] +pub union IfrIfru { + pub addr: SockAddrStorage, + pub flags: ffi::c_short, + pub ifindex: ffi::c_int, + pub metric: ffi::c_int, + pub mtu: ffi::c_int, + pub slave: [u8; IF_NAME_SIZE], + pub newname: [u8; IF_NAME_SIZE], + pub data: *mut u8, +} + +#[repr(C)] +pub struct IfReq { + /// interface name, e.g. "en0" + pub name: [u8; IF_NAME_SIZE], + pub data: IfrIfru, +} + +impl IfReq { + /// Get the interface name, e.g. "en0". [`None`] is returned if UTF-8 + /// validation failed. + pub fn name(&self) -> Option<&str> { + let null_index = self.name.iter().position(|&x| x == 0).unwrap_or_default(); + let name = &self.name[..null_index]; + core::str::from_utf8(name).ok() + } +} diff --git a/src/aero_syscall/src/lib.rs b/src/aero_syscall/src/lib.rs index 48048b024a4..03c7132aaf5 100644 --- a/src/aero_syscall/src/lib.rs +++ b/src/aero_syscall/src/lib.rs @@ -1,31 +1,42 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #![no_std] -#![feature(decl_macro)] +// #![feature(decl_macro)] +// cc +#![allow(clippy::bad_bit_mask)] + +#[macro_use] +extern crate num_derive; pub mod consts; +pub mod netlink; pub mod signal; pub mod socket; pub mod syscall; pub mod time; +pub type Result = core::result::Result; + +use core::ffi; +use core::time::Duration; + +use byte_endian::BigEndian; + pub use crate::syscall::*; pub mod prelude { @@ -55,30 +66,56 @@ bitflags::bitflags! { bitflags::bitflags! { pub struct OpenFlags: usize { - const O_ACCMODE = 0x0007; - const O_EXEC = 1; - const O_RDONLY = 2; - const O_RDWR = 3; - const O_SEARCH = 4; - const O_WRONLY = 5; - const O_APPEND = 0x0008; - const O_CREAT = 0x0010; - const O_DIRECTORY = 0x0020; - const O_EXCL = 0x0040; - const O_NOCTTY = 0x0080; - const O_NOFOLLOW = 0x0100; - const O_TRUNC = 0x0200; - const O_NONBLOCK = 0x0400; - const O_DSYNC = 0x0800; - const O_RSYNC = 0x1000; - const O_SYNC = 0x2000; - const O_CLOEXEC = 0x4000; - const O_PATH = 0x8000; + const O_PATH = 0o10000000; + + const O_ACCMODE = (0o3 | Self::O_PATH.bits()); + const O_RDONLY = 0o0; + const O_WRONLY = 0o1; + const O_RDWR = 0o2; + + const O_SEARCH = Self::O_PATH.bits(); + const O_EXEC = Self::O_PATH.bits(); + + const O_CREAT = 0o100; + const O_EXCL = 0o200; + const O_NOCTTY = 0o400; + const O_TRUNC = 0o1000; + const O_APPEND = 0o2000; + const O_NONBLOCK = 0o4000; + const O_DSYNC = 0o10000; + const O_ASYNC = 0o20000; + const O_DIRECT = 0o40000; + const O_DIRECTORY = 0o200000; + const O_NOFOLLOW = 0o400000; + const O_CLOEXEC = 0o2000000; + const O_SYNC = 0o4010000; + const O_RSYNC = 0o4010000; + const O_LARGEFILE = 0o100000; + const O_NOATIME = 0o1000000; + const O_TMPFILE = 0o20000000; + } +} + +impl OpenFlags { + pub fn is_nonblock(&self) -> bool { + self.contains(Self::O_NONBLOCK) + } +} + +bitflags::bitflags! { + pub struct WaitPidFlags: usize { + const WNOHANG = 1; + const WUNTRACED = 2; + const WSTOPPED = 2; + const WEXITED = 4; + const WCONTINUED = 8; + const WNOWAIT = 0x01000000; } } #[derive(Copy, Clone, PartialEq, Debug)] #[repr(isize)] +#[allow(clippy::enum_clike_unportable_variant)] pub enum SyscallError { EDOM = 1, EILSEQ = 2, @@ -169,82 +206,17 @@ pub enum SyscallError { Unknown = isize::MAX, } -pub fn syscall_as_str(syscall: usize) -> &'static str { - match syscall { - prelude::SYS_READ => "read", - prelude::SYS_WRITE => "write", - prelude::SYS_OPEN => "open", - prelude::SYS_CLOSE => "close", - prelude::SYS_SHUTDOWN => "shutdown", - prelude::SYS_EXIT => "exit", - prelude::SYS_FORK => "fork", - prelude::SYS_REBOOT => "reboot", - prelude::SYS_MMAP => "mmap", - prelude::SYS_MUNMAP => "munmap", - prelude::SYS_ARCH_PRCTL => "arch_prctl", - prelude::SYS_GETDENTS => "getdents", - prelude::SYS_GETCWD => "getcwd", - prelude::SYS_CHDIR => "chdir", - prelude::SYS_MKDIR => "mkdir", - prelude::SYS_MKDIR_AT => "mkdir_at", - prelude::SYS_RMDIR => "rmdir", - prelude::SYS_EXEC => "exec", - prelude::SYS_LOG => "log", - prelude::SYS_UNAME => "uname", - prelude::SYS_WAITPID => "waitpid", - prelude::SYS_IOCTL => "ioctl", - prelude::SYS_GETPID => "getpid", - prelude::SYS_SOCKET => "socket", - prelude::SYS_CONNECT => "connect", - prelude::SYS_BIND => "bind", - prelude::SYS_LISTEN => "listen", - prelude::SYS_ACCEPT => "accept", - prelude::SYS_SEEK => "seek", - prelude::SYS_GETTID => "gettid", - prelude::SYS_GETTIME => "gettime", - prelude::SYS_SLEEP => "sleep", - prelude::SYS_ACCESS => "access", - prelude::SYS_PIPE => "pipe", - prelude::SYS_UNLINK => "unlink", - prelude::SYS_GETHOSTNAME => "gethostname", - prelude::SYS_SETHOSTNAME => "sethostname", - prelude::SYS_INFO => "info", - prelude::SYS_CLONE => "clone", - prelude::SYS_SIGRETURN => "sigreturn", - prelude::SYS_SIGACTION => "sigaction", - prelude::SYS_SIGPROCMASK => "sigprocmask", - prelude::SYS_DUP => "dup", - prelude::SYS_FCNTL => "fcntl", - prelude::SYS_DUP2 => "dup2", - prelude::SYS_IPC_SEND => "ipc_send", - prelude::SYS_IPC_RECV => "ipc_recv", - prelude::SYS_IPC_DISCOVER_ROOT => "ipc_discover_root", - prelude::SYS_IPC_BECOME_ROOT => "ipc_become_root", - prelude::SYS_STAT => "stat", - prelude::SYS_FSTAT => "fstat", - prelude::SYS_READ_LINK => "readlink", - prelude::SYS_EPOLL_CREATE => "epoll_create", - prelude::SYS_EPOLL_PWAIT => "epoll_pwait", - prelude::SYS_EPOLL_CTL => "epoll_ctl", - prelude::SYS_EVENT_FD => "event_fd", - prelude::SYS_KILL => "kill", - prelude::SYS_FUTEX_WAIT => "futex_wait", - prelude::SYS_FUTEX_WAKE => "futex_wake", - prelude::SYS_LINK => "link", - prelude::SYS_BACKTRACE => "backtrace", - prelude::SYS_POLL => "poll", - - _ => unreachable!("unknown syscall {syscall}"), - } -} - #[derive(Debug)] #[repr(usize)] pub enum SysFileType { - File, - Directory, - Device, - Socket, + Unknown = 0, + Fifo = 1, + CharDevice = 2, + Directory = 4, + BlockDevice = 6, + File = 8, + Symlink = 10, + Socket = 12, } #[repr(C, packed)] @@ -256,19 +228,20 @@ pub struct SysDirEntry { pub name: [u8; 0], } -#[derive(Debug)] #[repr(C)] +#[derive(Debug)] pub struct Utsname { - pub name: [u8; 65], + pub sysname: [u8; 65], pub nodename: [u8; 65], pub release: [u8; 65], pub version: [u8; 65], pub machine: [u8; 65], + pub domainname: [u8; 65], } impl Utsname { pub fn name(&self) -> &str { - unsafe { core::str::from_utf8_unchecked(&self.name) } + unsafe { core::str::from_utf8_unchecked(&self.sysname) } } pub fn nodename(&self) -> &str { @@ -291,11 +264,12 @@ impl Utsname { impl Default for Utsname { fn default() -> Self { Self { - name: [0; 65], + sysname: [0; 65], nodename: [0; 65], release: [0; 65], version: [0; 65], machine: [0; 65], + domainname: [0; 65], } } } @@ -307,8 +281,18 @@ pub struct TimeSpec { pub tv_nsec: isize, } +impl From for TimeSpec { + #[inline] + fn from(value: Duration) -> Self { + TimeSpec { + tv_sec: value.as_secs() as isize, + tv_nsec: value.subsec_nanos() as isize, + } + } +} + #[repr(usize)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum SeekWhence { SeekCur = 1, SeekEnd = 2, @@ -327,10 +311,15 @@ impl From for SeekWhence { } pub const TIOCGWINSZ: usize = 0x5413; +pub const TIOCSWINSZ: usize = 0x5414; pub const TCGETS: usize = 0x5401; +pub const TCSETSW: usize = 0x5403; pub const TCSETSF: usize = 0x5404; +pub const TIOCSCTTY: usize = 0x540e; +pub const TIOCNOTTY: usize = 0x5422; +pub const TIOCGPGRP: usize = 0x540f; -#[derive(Default)] +#[derive(Default, Debug, Copy, Clone)] #[repr(C)] pub struct WinSize { pub ws_row: u16, @@ -339,87 +328,138 @@ pub struct WinSize { pub ws_ypixel: u16, } +// indices for the c_cc array in struct termios +// +// abis/linux/termios.h +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VTIME: usize = 5; +pub const VMIN: usize = 6; +pub const VSWTC: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VEOL: usize = 11; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const VLNEXT: usize = 15; +pub const VEOL2: usize = 16; + +bitflags::bitflags! { + #[derive(Default)] + pub struct TermiosIFlag: u32 { + const BRKINT = 0o000002; + const ICRNL = 0o000400; + const IGNBRK = 0o000001; + const IGNCR = 0o000200; + const IGNPAR = 0o000004; + const INLCR = 0o000100; + const INPCK = 0o000020; + const ISTRIP = 0o000040; + const IXANY = 0o004000; + const IXOFF = 0o010000; + const IXON = 0o002000; + const PARMRK = 0o000010; + } +} + bitflags::bitflags! { #[derive(Default)] pub struct TermiosLFlag: u32 { - const ECHO = 0x0001; - const ECHOE = 0x0002; - const ECHOK = 0x0004; - const ECHONL = 0x0008; - const ICANON = 0x0010; - const IEXTEN = 0x0020; - const ISIG = 0x0040; - const NOFLSH = 0x0080; - const TOSTOP = 0x0100; - const ECHOPRT= 0x0200; + const ECHO = 0x8; + const ECHOE = 0x10; + const ECHOK = 0x20; + const ECHONL = 0x40; + const ICANON = 0x2; + const IEXTEN = 0x8000; + const ISIG = 0x1; + const NOFLSH = 0x80; + const TOSTOP = 0x100; + const ECHOPRT = 0x400; + // options/posix/include/termios.h + const ECHOCTL = 0o001000; + const FLUSHO = 0o010000; + const IMAXBEL = 0o020000; + const ECHOKE = 0o040000; } } bitflags::bitflags! { #[derive(Default)] pub struct TermiosCFlag: u32 { - const CSIZE = 0x0003; - const CS5 = 0x0000; - const CS6 = 0x0001; - const CS7 = 0x0002; - const CS8 = 0x0003; - const CSTOPB = 0x0004; - const CREAD = 0x0008; - const PARENB = 0x0010; - const PARODD = 0x0020; - const HUPCL = 0x0040; - const CLOCAL = 0x0080; + const CSIZE = 0x30; + const CS5 = 0x0; + const CS6 = 0x10; + const CS7 = 0x20; + const CS8 = 0x30; + const CSTOPB = 0x40; + const CREAD = 0x80; + const PARENB = 0x100; + const PARODD = 0x200; + const HUPCL = 0x400; + const CLOCAL = 0x800; } } bitflags::bitflags! { #[derive(Default)] pub struct TermiosOFlag: u32 { - const OPOST = 0x0001; - const ONLCR = 0x0002; - const OCRNL = 0x0004; - const ONOCR = 0x0008; - const ONLRET = 0x0010; - const OFDEL = 0x0020; - const OFILL = 0x0040; - const NLDLY = 0x0080; - const NL0 = 0x0000; - const NL1 = 0x0080; - const CRDLY = 0x0300; - const CR0 = 0x0000; - const CR1 = 0x0100; - const CR2 = 0x0200; - const CR3 = 0x0300; - const TABDLY = 0x0C00; - const TAB0 = 0x0000; - const TAB1 = 0x0400; - const TAB2 = 0x0800; - const TAB3 = 0x0C00; - const BSDLY = 0x1000; - const BS0 = 0x0000; - const BS1 = 0x1000; - const VTDLY = 0x2000; - const VT0 = 0x0000; - const VT1 = 0x2000; - const FFDLY = 0x4000; - const FF0 = 0x0000; - const FF1 = 0x4000; + const OPOST = 0x1; + const ONLCR = 0x4; + const OCRNL = 0x8; + const ONOCR = 0x10; + const ONLRET = 0x20; + const OFDEL = 0x80; + const OFILL = 0x40; + const NLDLY = 0x100; + const NL0 = 0x0; + const NL1 = 0x100; + const CRDLY = 0x600; + const CR0 = 0x0; + const CR1 = 0x200; + const CR2 = 0x400; + const CR3 = 0x600; + const TABDLY = 0x1800; + const TAB0 = 0x0; + const TAB1 = 0x800; + const TAB2 = 0x1000; + const TAB3 = 0x1800; + const XTABS = 0x1800; + const BSDLY = 0x2000; + const BS0 = 0x0; + const BS1 = 0x2000; + const VTDLY = 0x4000; + const VT0 = 0x0; + const VT1 = 0x4000; + const FFDLY = 0x8000; + const FF0 = 0x0; + const FF1 = 0x8000; } } #[derive(Debug, Default, Clone)] #[repr(C)] pub struct Termios { - pub c_iflag: u32, + pub c_iflag: TermiosIFlag, pub c_oflag: TermiosOFlag, pub c_cflag: TermiosCFlag, pub c_lflag: TermiosLFlag, pub c_line: u8, - pub c_cc: [u8; 11], + pub c_cc: [u8; 32], pub c_ispeed: u32, pub c_ospeed: u32, } +impl Termios { + pub fn is_cooked(&self) -> bool { + self.c_lflag.contains(TermiosLFlag::ICANON) + } +} + pub const AT_FDCWD: isize = -100; #[repr(C)] @@ -449,7 +489,7 @@ pub struct SysInfo { pub _f: [i8; 0], } -pub fn syscall_result_as_usize(result: Result) -> usize { +pub fn syscall_result_as_usize(result: Result) -> usize { match result { Ok(value) => value as _, Err(error) => -(error as isize) as _, @@ -458,7 +498,7 @@ pub fn syscall_result_as_usize(result: Result) -> usize { /// Inner helper function that converts the syscall result value into the /// Rust [`Result`] type. -pub fn isize_as_syscall_result(value: isize) -> Result { +pub fn isize_as_syscall_result(value: isize) -> Result { if value >= 0 { Ok(value as usize) } else { @@ -467,203 +507,39 @@ pub fn isize_as_syscall_result(value: isize) -> Result { } } -pub fn sys_exit(status: usize) -> ! { - syscall1(prelude::SYS_EXIT, status); - unreachable!() -} - -pub fn sys_open(path: &str, mode: OpenFlags) -> Result { - let value = syscall4( - prelude::SYS_OPEN, - 0x00, - path.as_ptr() as usize, - path.len(), - mode.bits(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_write(fd: usize, buf: &[u8]) -> Result { - let value = syscall3( - prelude::SYS_WRITE, - fd as usize, - buf.as_ptr() as usize, - buf.len(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_read(fd: usize, buf: &mut [u8]) -> Result { +pub fn sys_ipc_send(pid: usize, message: &[u8]) -> Result<()> { let value = syscall3( - prelude::SYS_READ, - fd as usize, - buf.as_mut_ptr() as usize, - buf.len(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_chdir(path: &str) -> Result { - let value = syscall2(prelude::SYS_CHDIR, path.as_ptr() as usize, path.len()); - isize_as_syscall_result(value as _) -} - -pub fn sys_close(fd: usize) -> Result { - let value = syscall1(prelude::SYS_CLOSE, fd); - isize_as_syscall_result(value as _) -} - -pub fn sys_getcwd(buf: &mut [u8]) -> Result { - let value = syscall2(prelude::SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()); - isize_as_syscall_result(value as _) -} - -pub fn sys_getdents(fd: usize, buf: &mut [u8]) -> Result { - let value = syscall3( - prelude::SYS_GETDENTS, - fd as usize, - buf.as_mut_ptr() as usize, - buf.len(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_fork() -> Result { - let value = syscall0(prelude::SYS_FORK); - isize_as_syscall_result(value as _) -} - -pub fn sys_munmap(address: usize, size: usize) -> Result { - let value = syscall2(prelude::SYS_MUNMAP, address as usize, size as usize); - isize_as_syscall_result(value as _) -} - -pub fn sys_mkdir(path: &str) -> Result { - let value = syscall2(prelude::SYS_MKDIR, path.as_ptr() as usize, path.len()); - isize_as_syscall_result(value as _) -} - -pub fn sys_log(message: &str) -> Result { - let value = syscall2(prelude::SYS_LOG, message.as_ptr() as usize, message.len()); - isize_as_syscall_result(value as _) -} - -pub fn sys_mkdirat(dfd: isize, path: &str) -> Result { - let value = syscall3( - prelude::SYS_MKDIR_AT, - dfd as usize, - path.as_ptr() as usize, - path.len(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_exec(path: &str, argv: &[&str], envv: &[&str]) -> Result { - let value = syscall6( - prelude::SYS_EXEC, - path.as_ptr() as usize, - path.len(), - argv.as_ptr() as usize, - argv.len(), - envv.as_ptr() as usize, - envv.len(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_rmdir(path: &str) -> Result { - let value = syscall2(prelude::SYS_RMDIR, path.as_ptr() as usize, path.len()); - isize_as_syscall_result(value as _) -} - -pub fn sys_uname(struc: &mut Utsname) -> Result { - let value = syscall1(prelude::SYS_UNAME, struc as *mut Utsname as usize); - isize_as_syscall_result(value as _) -} - -pub fn sys_shutdown() -> ! { - syscall0(prelude::SYS_SHUTDOWN); - unreachable!() -} - -pub fn sys_access(fd: usize, path: &str) -> Result { - let value = syscall5( - prelude::SYS_ACCESS, - fd, - path.as_ptr() as usize, - path.len(), - 0, - 0, - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_waitpid(pid: usize, status: &mut u32, flags: usize) -> Result { - let value = syscall3( - prelude::SYS_WAITPID, - pid as usize, - status as *mut u32 as usize, - flags, + prelude::SYS_IPC_SEND, + pid, + message.as_ptr() as usize, + message.len(), ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_ioctl(fd: usize, command: usize, arg: usize) -> Result { - let value = syscall3(prelude::SYS_IOCTL, fd as usize, command, arg); - isize_as_syscall_result(value as _) + isize_as_syscall_result(value as _).map(|_| ()) } -pub fn sys_mmap( - address: usize, - size: usize, - protection: MMapProt, - flags: MMapFlags, - fd: usize, - offset: usize, -) -> Result { - let value = syscall6( - prelude::SYS_MMAP, - address, - size, - protection.bits(), - flags.bits(), - fd, - offset, +pub fn sys_ipc_recv<'a>( + pid: &mut usize, + message: &'a mut [u8], + block: bool, +) -> Result<&'a mut [u8]> { + let value = syscall4( + prelude::SYS_IPC_RECV, + pid as *mut usize as usize, + message.as_ptr() as usize, + message.len(), + block as usize, ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_getpid() -> Result { - let value = syscall0(prelude::SYS_GETPID); - isize_as_syscall_result(value as _) -} - -pub fn sys_gettid() -> Result { - let value = syscall0(prelude::SYS_GETTID); - isize_as_syscall_result(value as _) + isize_as_syscall_result(value as _).map(|size| &mut message[0..size]) } -pub fn sys_gethostname(buf: &mut [u8]) -> Result { - let value = syscall2( - prelude::SYS_GETHOSTNAME, - buf.as_mut_ptr() as usize, - buf.len(), - ); +pub fn sys_ipc_discover_root() -> Result { + let value = syscall0(prelude::SYS_IPC_DISCOVER_ROOT); isize_as_syscall_result(value as _) } -pub fn sys_sethostname(name: &str) -> Result { - let value = syscall2(prelude::SYS_SETHOSTNAME, name.as_ptr() as usize, name.len()); - isize_as_syscall_result(value as _) +pub fn sys_ipc_become_root() -> Result<()> { + let value = syscall0(prelude::SYS_IPC_BECOME_ROOT); + isize_as_syscall_result(value as _).map(|_| ()) } // Sockets @@ -676,6 +552,22 @@ pub struct SocketAddrUnix { pub path: [u8; 108], } +impl SocketAddrUnix { + pub fn path_len(&self) -> u8 { + if self.path[0] == 0 { + if self.path[1] == 0 { + // address is unnamed + return 0; + } else { + // abstract socket address + unimplemented!() + } + } + + (self.path.iter().position(|&c| c == 0).unwrap_or(108) as u8) + 1 + } +} + impl Default for SocketAddrUnix { fn default() -> Self { Self { @@ -685,30 +577,73 @@ impl Default for SocketAddrUnix { } } +#[derive(Debug, Clone)] +#[repr(C)] +pub struct InAddr { + pub addr: u32, +} + #[derive(Debug, Clone)] #[repr(C)] pub struct SocketAddrInet { pub family: u32, - pub port: [u8; 2], - pub address: [u8; 4], + pub port: BigEndian, + pub sin_addr: InAddr, pub padding: [u8; 8], } +impl SocketAddrInet { + pub fn addr(&self) -> [u8; 4] { + self.sin_addr.addr.to_le_bytes() + } + + pub fn port(&self) -> u16 { + self.port.to_native() + } +} + impl SocketAddr for SocketAddrUnix {} impl SocketAddr for SocketAddrInet {} -// constants for the socket types: -// -// mlibc/sysdeps/aero/include/abi-bits/socket.h -pub const SOCK_DGRAM: usize = 1; -pub const SOCK_RAW: usize = 2; -pub const SOCK_SEQPACKET: usize = 3; -pub const SOCK_STREAM: usize = 4; +// mlibc/abi-bits/mlibc/in.h +#[derive(Debug, Copy, Clone, FromPrimitive, PartialEq)] +pub enum IpProtocol { + Default = 0, + Ip = 1, + Ipv6 = 2, + Icmp = 3, + Raw = 4, + Tcp = 5, + Udp = 6, + Igmp = 7, + Ipip = 8, + Dccp = 33, + Routing = 43, + Gre = 47, + Esp = 50, + Ah = 51, + Icmpv6 = 58, + Dstopts = 60, + Comp = 108, + Sctp = 132, + Max = 256, +} + +// mlibc/abi-bits/mlibc/socket.h +#[derive(Debug, Copy, Clone, FromPrimitive, PartialEq)] +pub enum SocketType { + Dgram = 1, + Raw = 2, + SeqPacket = 3, + Stream = 4, + Dccp = 5, +} bitflags::bitflags! { pub struct SocketFlags: usize { const NONBLOCK = 0x10000; - const CLOEXEC = 0x20000; + const CLOEXEC = 0x20000; + const RDM = 0x40000; } } @@ -744,160 +679,7 @@ pub const AF_UNSPEC: u32 = PF_UNSPEC; pub const AF_NETLINK: u32 = PF_NETLINK; pub const AF_BRIDGE: u32 = PF_BRIDGE; -pub fn sys_socket( - domain: usize, - socket_type: usize, - protocol: usize, -) -> Result { - let value = syscall3(prelude::SYS_SOCKET, domain, socket_type, protocol); - isize_as_syscall_result(value as _) -} - -pub fn sys_listen(fd: usize, backlog: usize) -> Result { - let value = syscall2(prelude::SYS_LISTEN, fd, backlog); - isize_as_syscall_result(value as _) -} - -pub fn sys_unlink(fd: usize, path: &str, flags: OpenFlags) -> Result { - let value = syscall4( - prelude::SYS_UNLINK, - fd, - path.as_ptr() as usize, - path.len(), - flags.bits(), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_gettime(clock: usize, timespec: &mut TimeSpec) -> Result { - let value = syscall2(prelude::SYS_GETTIME, clock, timespec as *mut _ as usize); - isize_as_syscall_result(value as _) -} - -pub fn sys_seek(fd: usize, offset: usize, whence: SeekWhence) -> Result { - let value = syscall3(prelude::SYS_SEEK, fd, offset, whence as usize); - isize_as_syscall_result(value as _) -} - -pub fn sys_sleep(timespec: &TimeSpec) -> Result { - let value = syscall1(prelude::SYS_SLEEP, timespec as *const _ as usize); - isize_as_syscall_result(value as _) -} - -pub fn sys_pipe(fds: &mut [usize; 2], flags: OpenFlags) -> Result { - let value = syscall2(prelude::SYS_PIPE, fds.as_ptr() as usize, flags.bits()); - isize_as_syscall_result(value as _) -} - -pub fn sys_info(struc: &mut SysInfo) -> Result { - let value = syscall1(prelude::SYS_INFO, struc as *mut _ as usize); - isize_as_syscall_result(value as _) -} - -pub fn sys_clone(entry: usize, stack: usize) -> Result { - let value = syscall2(prelude::SYS_CLONE, entry, stack); - isize_as_syscall_result(value as _) -} - -pub fn sys_sigreturn() -> Result { - let value = syscall0(prelude::SYS_SIGRETURN); - isize_as_syscall_result(value as _) -} - -pub fn sys_sigaction( - sig: usize, - sigaction: Option<&signal::SigAction>, - old_sigaction: Option<&mut signal::SigAction>, -) -> Result { - let sigact = sigaction; - - let value = syscall4( - prelude::SYS_SIGACTION, - sig, - sigact - .and_then(|f| Some(f as *const signal::SigAction as usize)) - .unwrap_or(0), - sys_sigreturn as usize, - old_sigaction - .and_then(|f| Some(f as *mut signal::SigAction as usize)) - .unwrap_or(0), - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_sigprocmask( - how: signal::SigProcMask, - set: &mut u64, - old_set: Option<&mut u64>, -) -> Result { - let old_set = match old_set { - Some(e) => e as *const u64 as usize, - None => 0, - }; - - let value = syscall3( - prelude::SYS_SIGPROCMASK, - how as usize, - set as *const u64 as usize, - old_set, - ); - - isize_as_syscall_result(value as _) -} - -pub fn sys_dup(fd: usize, flags: OpenFlags) -> Result { - let value = syscall2(prelude::SYS_DUP, fd, flags.bits()); - isize_as_syscall_result(value as _) -} - -pub fn sys_fcntl(fd: usize, command: usize, argument: usize) -> Result { - let value = syscall3(prelude::SYS_FCNTL, fd, command, argument); - isize_as_syscall_result(value as _) -} - -pub fn sys_dup2(fd: usize, new_fd: usize, flags: OpenFlags) -> Result { - let value = syscall3(prelude::SYS_DUP2, fd, new_fd, flags.bits()); - isize_as_syscall_result(value as _) -} - -pub fn sys_ipc_send(pid: usize, message: &[u8]) -> Result<(), SyscallError> { - let value = syscall3( - prelude::SYS_IPC_SEND, - pid, - message.as_ptr() as usize, - message.len(), - ); - isize_as_syscall_result(value as _).map(|_| ()) -} - -pub fn sys_ipc_recv<'a>( - pid: &mut usize, - message: &'a mut [u8], - block: bool, -) -> Result<&'a mut [u8], SyscallError> { - let value = syscall4( - prelude::SYS_IPC_RECV, - pid as *mut usize as usize, - message.as_ptr() as usize, - message.len(), - block as usize, - ); - isize_as_syscall_result(value as _).map(|size| &mut message[0..size]) -} - -pub fn sys_ipc_discover_root() -> Result { - let value = syscall0(prelude::SYS_IPC_DISCOVER_ROOT); - isize_as_syscall_result(value as _) -} - -pub fn sys_ipc_become_root() -> Result<(), SyscallError> { - let value = syscall0(prelude::SYS_IPC_BECOME_ROOT); - isize_as_syscall_result(value as _).map(|_| ()) -} - -// sysdeps/aero/include/abi-bits/stat.h +// mlibc/abis/linux/stat.h bitflags::bitflags! { #[derive(Default)] pub struct Mode: u32 { @@ -910,21 +692,21 @@ bitflags::bitflags! { const S_IFLNK = 0x0A000; const S_IFSOCK = 0x0C000; - const S_IRWXU = 0700; - const S_IRUSR = 0400; - const S_IWUSR = 0200; - const S_IXUSR = 0100; - const S_IRWXG = 070; - const S_IRGRP = 040; - const S_IWGRP = 020; - const S_IXGRP = 010; - const S_IRWXO = 07; - const S_IROTH = 04; - const S_IWOTH = 02; - const S_IXOTH = 01; - const S_ISUID = 04000; - const S_ISGID = 02000; - const S_ISVTX = 01000; + const S_IRWXU = 0o700; + const S_IRUSR = 0o400; + const S_IWUSR = 0o200; + const S_IXUSR = 0o100; + const S_IRWXG = 0o70; + const S_IRGRP = 0o40; + const S_IWGRP = 0o20; + const S_IXGRP = 0o10; + const S_IRWXO = 0o7; + const S_IROTH = 0o4; + const S_IWOTH = 0o2; + const S_IXOTH = 0o1; + const S_ISUID = 0o4000; + const S_ISGID = 0o2000; + const S_ISVTX = 0o1000; const S_IREAD = Self::S_IRUSR.bits(); const S_IWRITE = Self::S_IWUSR.bits(); @@ -932,37 +714,50 @@ bitflags::bitflags! { } } -// sysdeps/aero/include/abi-bits/stat.h +// mlibc/abis/linux/stat.h +#[cfg(target_arch = "x86_64")] #[repr(C)] #[derive(Debug, Default)] pub struct Stat { pub st_dev: u64, pub st_ino: u64, - pub st_mode: Mode, pub st_nlink: u32, + pub st_mode: Mode, pub st_uid: u32, pub st_gid: u32, + // FIXME: make this private + pub __pad0: ffi::c_uint, pub st_rdev: u64, pub st_size: i64, + pub st_blksize: u64, + pub st_blocks: u64, pub st_atim: TimeSpec, pub st_mtim: TimeSpec, pub st_ctim: TimeSpec, - pub st_blksize: u64, - pub st_blocks: u64, -} - -pub fn sys_stat(path: &str, stat: &mut Stat) -> Result { - let value = syscall3( - prelude::SYS_STAT, - path.as_ptr() as usize, - path.len(), - stat as *mut Stat as usize, - ); - - isize_as_syscall_result(value as _) + // FIXME: make this private + pub __unused: [ffi::c_long; 3], } -pub fn sys_fstat(fd: usize, stat: &mut Stat) -> Result { - let value = syscall2(prelude::SYS_FSTAT, fd, stat as *mut Stat as usize); - isize_as_syscall_result(value as _) +bitflags::bitflags! { + // mlibc/abis/linux/fcntl.h + #[repr(transparent)] + pub struct AtFlags: usize { + /// Do not follow symbolic links. + const SYMLINK_NOFOLLOW = 0x100; + /// Remove directory instead of unlinking file. + const REMOVEDIR = 0x200; + /// Follow symbolic links. + const SYMLINK_FOLLOW = 0x400; + /// Test access permitted for effective IDs, not real IDs. + const EACCESS = 0x200; + /// Allow empty relative pathname. + const EMPTY_PATH = 0x1000; + + const STATX_FORCE_SYNC = 0x2000; + const STATX_DONT_SYNC = 0x4000; + const STATX_SYNC_TYPE = 0x6000; + + const STATX_SYNC_AS_STAT = 0x0000; + const NO_AUTOMOUNT = 0x800; + } } diff --git a/src/aero_syscall/src/netlink.rs b/src/aero_syscall/src/netlink.rs new file mode 100644 index 00000000000..23e2029f0bc --- /dev/null +++ b/src/aero_syscall/src/netlink.rs @@ -0,0 +1,230 @@ +#![allow(non_camel_case_types)] + +use static_assertions::const_assert_eq; + +const NLMSG_ALIGNTO: u32 = 4; + +/// Aligns `len` to the netlink message alignment. +/// +/// **Note**: This function only rounds up. +pub const fn nlmsg_align(len: u32) -> u32 { + (len + NLMSG_ALIGNTO - 1) & !(NLMSG_ALIGNTO - 1) +} + +const RTA_ALIGNTO: u32 = 4; + +pub const fn rta_align(len: u32) -> u32 { + (len + RTA_ALIGNTO - 1) & !(RTA_ALIGNTO - 1) +} + +pub const fn rta_length(len: u32) -> u32 { + rta_align(core::mem::size_of::() as u32) + len +} + +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(u16)] +pub enum RtAttrType { + Unspec, + Dst, + Src, + Iif, + Oif, + Gateway, + Priority, + PrefSrc, + Metrics, + Multipath, + ProtoInfo, // no longer used + Flow, + CacheInfo, + Session, // no longer used + MpAlgo, // no longer used + Table, + // RtaMARK, + // RtaMFC_STATS, + // RtaVIA, + // RtaNEWDST, + // RtaPREF, + // RtaENCAP_TYPE, + // RtaENCAP, + // RtaEXPIRES, + // RtaPAD, + // RtaUID, + // RtaTTL_PROPAGATE, + // RtaIP_PROTO, + // RtaSPORT, + // RtaDPORT, + // RtaNH_ID, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(u16)] +pub enum MessageType { + Noop, + Error, + Done, // end of a dump + Overrun, // data lost + + // RTM + RtmNewLink = 16, + RtmDelLink, + RtmGetLink, + RtmSetLink, + RtmNewAddr, + RtmDelAddr, + RtmGetAddr, + RtmNewRoute = 24, + RtmDelRoute, + RtmGetRoute, + RtmNewNeigh = 28, + RtmDelNeigh, + RtmGetNeigh, + RtmNewRule = 32, + RtmDelRule, + RtmGetRule, + RtmNewQDisc = 36, + RtmDelQDisc, + RtmGetQDisc, + RtmNewTClass = 40, + RtmDelTClass, + RtmGetTClass, + RtmNewTFilter = 44, + RtmDelTFilter, + RtmGetTFilter, + RtmNewAction = 48, + RtmDelAction, + RtmGetAction, + RtmNewPrefix = 52, + RtmGetMulticast = 58, + RtmGetAnyCast = 62, + RtmNewNeighTbl = 64, + RtmGetNeighTbl = 66, + RtmSetNeighTbl = 67, + RtmNewNdUserOpt = 68, + RtmNewAddrLabel = 72, + RtmDelAddrLabel, + RtmGetAddrLabel, + RtmGetDcb = 78, + RtmSetDcb, + RtmNewNetConf = 80, + RtmDelNetConf, + RtmGetNetConf, + RtmNewMdb = 84, + RtmDelMdb, + RtmGetMdb, + RtmNewNsid = 88, + RtmDelNsid, + RtmGetNsid, + RtmNewStats = 92, + RtmGetStats = 94, + RtmSetStats = 95, + RtmNewCacheReport = 96, + RtmNewChain = 100, + RtmDelChain, + RtmGetChain, + RtmNewNextHop = 104, + RtmDelNextHop, + RtmGetNextHop, + RtmNewLinkProp = 108, + RtmDelLinkProp, + RtmGetLinkProp, + RtmNewVlan = 112, + RtmDelVlan, + RtmGetVlan, + RtmNewNextHopBucket = 116, + RtmDelNextHopBucket, + RtmGetNextHopBucket, + RtmNewTunnel = 120, + RtmDelTunnel, + RtmGetTunnel, + + Unknown = u16::MAX, +} + +bitflags::bitflags! { + #[repr(transparent)] + pub struct MessageFlags: u16 { + const REQUEST = 0x1; // It is a request message. + const MULTI = 0x2; // Multipart message, terminated by NLMSG_DONE. + const ACK = 0x4; // Reply with ack, with zero or error code. + const ECHO = 0x8; // Echo this request. + const DUMP_INTR = 0x10; // Dump was inconsistent due to sequence change. + const DUMP_FILTERED = 0x20; // Dump was filtered as requested. + + // Modifers to GET request. + const ROOT = 0x100; // specify tree root. + const MATCH = 0x200; // return all matching. + const ATOMIC = 0x400; // atomic GET. + const DUMP = MessageFlags::ROOT.bits() | MessageFlags::MATCH.bits(); + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct sockaddr_nl { + pub nl_family: u32, // AF_NETLINK + pub nl_pad: u16, // zero + pub nl_pid: u32, // port ID + pub nl_groups: u32, // multicast groups mask +} + +impl super::SocketAddr for sockaddr_nl {} + +/// Fixed format metadata header of Netlink messages. +#[derive(Debug)] +#[repr(C)] +pub struct nlmsghdr { + /// Length of message including header. + pub nlmsg_len: u32, + /// Message content type. + pub nlmsg_type: MessageType, + // Additional flags. + pub nlmsg_flags: MessageFlags, + /// Sequence number. + pub nlmsg_seq: u32, + /// Sending process port ID. + pub nlmsg_pid: u32, +} + +const_assert_eq!(core::mem::size_of::(), 16); + +/// General form of address family dependent message. +#[derive(Debug)] +#[repr(C)] +pub struct rtgenmsg { + pub rtgen_family: u8, +} + +const_assert_eq!(core::mem::size_of::(), 1); + +#[repr(C)] +#[derive(Debug)] +pub struct rtmsg { + pub rtm_family: u8, + pub rtm_dst_len: u8, + pub rtm_src_len: u8, + pub rtm_tos: u8, + pub rtm_table: u8, + pub rtm_protocol: u8, + pub rtm_scope: u8, + pub rtm_type: u8, + pub rtm_flags: u32, +} + +const_assert_eq!(core::mem::size_of::(), 12); + +// FIXME(andypython): This should be an enum. +// +// Reserved table identifiers. +pub const RT_TABLE_UNSPEC: u8 = 0; +// User defined values. +pub const RT_TABLE_DEFAULT: u8 = 253; +pub const RT_TABLE_MAIN: u8 = 254; +pub const RT_TABLE_LOCAL: u8 = 255; + +// Generic structure for encapsulation of optional route information. It is reminiscent of sockaddr, +// but with sa_family replaced with attribute type. +pub struct rtattr { + pub rta_len: u16, + pub rta_type: RtAttrType, +} diff --git a/src/aero_syscall/src/signal.rs b/src/aero_syscall/src/signal.rs index 30eb2ad6e1d..f0037aae990 100644 --- a/src/aero_syscall/src/signal.rs +++ b/src/aero_syscall/src/signal.rs @@ -1,18 +1,48 @@ -pub const SIGHUP: usize = 1; +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +// mlibc/abis/linux/signal.h +pub const SIGABRT: usize = 6; +pub const SIGFPE: usize = 8; +pub const SIGILL: usize = 4; pub const SIGINT: usize = 2; +pub const SIGSEGV: usize = 11; +pub const SIGTERM: usize = 15; +pub const SIGPROF: usize = 27; +pub const SIGIO: usize = 29; +pub const SIGPWR: usize = 30; +pub const SIGRTMIN: usize = 35; +pub const SIGRTMAX: usize = 64; + +// constants for sigprocmask() +pub const SIG_BLOCK: u64 = 0; +pub const SIG_UNBLOCK: u64 = 1; +pub const SIG_SETMASK: u64 = 2; + +pub const SIGHUP: usize = 1; pub const SIGQUIT: usize = 3; -pub const SIGILL: usize = 4; pub const SIGTRAP: usize = 5; -pub const SIGABRT: usize = 6; +pub const SIGIOT: usize = SIGABRT; pub const SIGBUS: usize = 7; -pub const SIGFPE: usize = 8; pub const SIGKILL: usize = 9; pub const SIGUSR1: usize = 10; -pub const SIGSEGV: usize = 11; pub const SIGUSR2: usize = 12; pub const SIGPIPE: usize = 13; pub const SIGALRM: usize = 14; -pub const SIGTERM: usize = 15; pub const SIGSTKFLT: usize = 16; pub const SIGCHLD: usize = 17; pub const SIGCONT: usize = 18; @@ -24,107 +54,107 @@ pub const SIGURG: usize = 23; pub const SIGXCPU: usize = 24; pub const SIGXFSZ: usize = 25; pub const SIGVTALRM: usize = 26; -pub const SIGPROF: usize = 27; pub const SIGWINCH: usize = 28; -pub const SIGIO: usize = 29; -pub const SIGPOLL: usize = SIGIO; -pub const SIGPWR: usize = 30; +pub const SIGPOLL: usize = 29; pub const SIGSYS: usize = 31; -pub const SIGRTMIN: usize = 32; -pub const SIGRTMAX: usize = 33; -pub const SIGCANCEL: usize = 34; +pub const SIGUNUSED: usize = SIGSYS; +pub const SIGCANCEL: usize = 32; + +pub const SIG_ERR: i64 = -1; // error +pub const SIG_DFL: i64 = 0; // default +pub const SIG_IGN: i64 = 1; // ignore -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] pub enum SignalHandler { Ignore, + #[default] Default, - Handle(fn(usize)), + Handle(extern "C" fn(usize)), +} + +impl From for SignalHandler { + fn from(v: u64) -> Self { + let v = v as i64; + match v { + SIG_IGN => SignalHandler::Ignore, + SIG_DFL => SignalHandler::Default, + v => SignalHandler::Handle(unsafe { + core::mem::transmute::(v as u64) + }), + } + } +} + +impl From for usize { + fn from(h: SignalHandler) -> Self { + match h { + SignalHandler::Ignore => SIG_IGN as usize, + SignalHandler::Default => SIG_DFL as usize, + SignalHandler::Handle(f) => f as usize, + } + } +} + +impl From for u64 { + fn from(h: SignalHandler) -> Self { + match h { + SignalHandler::Ignore => SIG_IGN as u64, + SignalHandler::Default => SIG_DFL as u64, + #[allow(clippy::fn_to_numeric_cast)] + SignalHandler::Handle(f) => f as u64, + } + } } #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct SigAction { pub sa_handler: u64, - pub sa_mask: u64, - pub sa_flags: u32, + pub sa_flags: u64, pub sa_sigaction: u64, + pub sa_mask: u64, } impl SigAction { pub fn new(handler: SignalHandler, mask: u64, flags: SignalFlags) -> SigAction { SigAction { sa_handler: handler.into(), - sa_mask: mask, sa_flags: flags.bits(), sa_sigaction: 0, + sa_mask: mask, } } } bitflags::bitflags! { + // mlibc/abis/linux/signal.h #[derive(Default)] - pub struct SignalFlags: u32 { - const SA_NOCLDSTOP = (1 << 0); - const SA_ONSTACK = (1 << 1); - const SA_RESETHAND = (1 << 2); - const SA_RESTART = (1 << 3); - const SA_SIGINFO = (1 << 4); - const SA_NOCLDWAIT = (1 << 5); - const SA_NODEFER = (1 << 6); + pub struct SignalFlags: u64 { + const SA_NOCLDSTOP = 1; + const SA_NOCLDWAIT = 2; + const SA_SIGINFO = 4; + const SA_ONSTACK = 0x08000000; + const SA_RESTART = 0x10000000; + const SA_NODEFER = 0x40000000; + const SA_RESETHAND = 0x80000000; + const SA_RESTORER = 0x04000000; } } #[repr(u64)] #[derive(Debug)] pub enum SigProcMask { - Block = 1, - Unblock = 2, - Set = 3, -} - -impl Default for SignalHandler { - fn default() -> Self { - SignalHandler::Default - } -} - -impl From for SignalHandler { - fn from(v: u64) -> Self { - let v = v as i64; - match v { - -3 => SignalHandler::Ignore, - -2 => SignalHandler::Default, - v => SignalHandler::Handle(unsafe { core::mem::transmute::(v as u64) }), - } - } -} - -impl From for usize { - fn from(h: SignalHandler) -> Self { - match h { - SignalHandler::Ignore => -3isize as usize, - SignalHandler::Default => -2isize as usize, - SignalHandler::Handle(f) => f as usize, - } - } -} - -impl From for u64 { - fn from(h: SignalHandler) -> Self { - match h { - SignalHandler::Ignore => -3isize as u64, - SignalHandler::Default => -2isize as u64, - SignalHandler::Handle(f) => f as u64, - } - } + Block = SIG_BLOCK, + Unblock = SIG_UNBLOCK, + Set = SIG_SETMASK, } impl From for SigProcMask { fn from(v: u64) -> Self { match v { - 1 => SigProcMask::Block, - 2 => SigProcMask::Unblock, - 3 => SigProcMask::Set, + SIG_BLOCK => SigProcMask::Block, + SIG_UNBLOCK => SigProcMask::Unblock, + SIG_SETMASK => SigProcMask::Set, _ => panic!("invalid signal procmask {}", v), } } diff --git a/src/aero_syscall/src/socket.rs b/src/aero_syscall/src/socket.rs index a01d2f65b0c..c1c13378a30 100644 --- a/src/aero_syscall/src/socket.rs +++ b/src/aero_syscall/src/socket.rs @@ -1,21 +1,62 @@ +#![allow(non_camel_case_types)] + use crate::SocketAddr; -// sysdeps/aero/include/abi-bits/socket.h +mod c { + // This should be bindgened. + pub type socklen_t = u32; + + pub const SCM_RIGHTS: i32 = 1; + pub const SCM_CREDENTIALS: i32 = 2; + + pub const SOL_SOCKET: i32 = 1; + pub const SOL_IPV6: i32 = 41; + pub const SOL_PACKET: i32 = 263; + pub const SOL_NETLINK: i32 = 270; +} + +bitflags::bitflags! { + // mlibc/abis/mlibc/socket.h + pub struct MessageFlags: usize { + /// Indicates that some control data was discarded due to lack of space in the + /// buffer for ancillary data. + const CTRUNC = 0x1; + const DONTROUTE = 0x2; + const EOR = 0x4; + const OOB = 0x8; + /// Requests not to send `SIGPIPE` on errors on stream oriented sockets when the + /// other end breaks the connection. The `EPIPE` error is still returned. + const NOSIGNAL = 0x10; + const PEEK = 0x20; + const TRUNC = 0x40; + const WAITALL = 0x80; + const FIN = 0x200; + const CONFIRM = 0x800; + + // Linux extensions. + const DONTWAIT = 0x1000; + const CMSG_CLOEXEC = 0x2000; + const MORE = 0x4000; + const FASTOPEN = 0x20000000; + } +} + +// mlibc/abis/mlibc/socket.h #[derive(Debug)] #[repr(C)] pub struct MessageHeader { /// Pointer to the socket address structure. name: *mut u8, /// Size of the socket address structure. - name_len: usize, + name_len: c::socklen_t, iovec: *mut IoVec, // todo: use Option> iovec_len: i32, // todo: use ffi::c_int control: *const u8, - control_len: usize, + control_len: c::socklen_t, - flags: i32, // todo: use ffi::c_int + pub flags: i32, // todo: use ffi::c_int } impl MessageHeader { @@ -24,28 +65,27 @@ impl MessageHeader { return None; } - assert!(self.name_len == core::mem::size_of::()); + assert!(self.name_len >= core::mem::size_of::() as u32); - // SAFETY: We know that the `name` pointer is valid and we have an exclusive reference to it. - // The size of name is checked above with the size of `T` and `T` is a `SocketAddr` so, its - // safe to create a mutable reference of `T` from the ptr. unsafe { Some(&mut *(self.name as *mut T)) } } pub fn iovecs(&self) -> &[IoVec] { - // SAFETY: We know that the `iovec` pointer is valid, initialized. unsafe { core::slice::from_raw_parts(self.iovec, self.iovec_len as usize) } } pub fn iovecs_mut(&mut self) -> &mut [IoVec] { - // SAFETY: We know that the `iovec` pointer is valid, initialized and we have - // exclusive access so, its safe to construct a mutable slice from it. unsafe { core::slice::from_raw_parts_mut(self.iovec, self.iovec_len as usize) } } + + pub fn control(&self) -> &[ControlMessage] { + assert!(self.control_len == 0); + &[] + } } // options/posix/include/bits/posix/iovec.h -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct IoVec { base: *mut u8, // todo: use Option> @@ -53,9 +93,14 @@ pub struct IoVec { } impl IoVec { - pub fn as_mut_slice(&mut self) -> &mut [u8] { - // SAFETY: We know that the `base` pointer is valid, initialized and we have - // exclusive access so, its safe to construct a mutable slice from it. + pub fn as_slice(&self) -> &[u8] { + // SAFETY: We know that the `base` pointer is valid and initialized. + unsafe { core::slice::from_raw_parts_mut(self.base, self.len) } + } + + pub fn as_slice_mut(&mut self) -> &mut [u8] { + // SAFETY: We know that the `base` pointer is valid, initialized and we have exclusive + // access so, its safe to construct a mutable slice from it. unsafe { core::slice::from_raw_parts_mut(self.base, self.len) } } @@ -64,3 +109,32 @@ impl IoVec { self.len } } + +/// Control Message Header (`struct cmsghdr`). +#[derive(Debug)] +#[repr(C)] +pub struct ControlMessage { + /// Data byte count, including the header. + pub cmsg_len: c::socklen_t, + /// Originating protocol. + pub cmsg_level: SocketOptionLevel, + /// Protocol-specific type. + pub cmsg_type: ControlMessageType, + // followed by cmsg_data: [u8; cmsg_len - sizeof(struct cmsghdr)] +} + +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(i32)] +pub enum ControlMessageType { + Rights = c::SCM_RIGHTS, + Credentials = c::SCM_CREDENTIALS, +} + +#[derive(Debug, Copy, Clone, PartialEq, FromPrimitive)] +#[repr(i32)] +pub enum SocketOptionLevel { + Socket = c::SOL_SOCKET, + Ipv6 = c::SOL_IPV6, + Packet = c::SOL_PACKET, + Netlink = c::SOL_NETLINK, +} diff --git a/src/aero_syscall/src/syscall.rs b/src/aero_syscall/src/syscall.rs index 9d0f44364b6..f699c6f03f6 100644 --- a/src/aero_syscall/src/syscall.rs +++ b/src/aero_syscall/src/syscall.rs @@ -1,45 +1,45 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use core::arch::asm; -macro define_syscall_fns($(pub fn $sys_fn:ident($a:ident $(,$b:ident $(,$c:ident $(,$d:ident $(,$e:ident $(,$f:ident $(,$g:ident)?)?)?)?)?)?) -> usize;)+) { - $( - pub fn $sys_fn(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize, $($g: usize)?)?)?)?)?)?) -> usize { - #[cfg(target_arch = "x86_64")] - unsafe { - asm!( - "syscall", - inout("rax") $a, - $(in("rdi") $b, $(in("rsi") $c, $(in("rdx") $d, $(in("r10") $e, $(in("r8") $f, $(in("r9") $g,)?)?)?)?)?)? - out("rcx") _, - out("r11") _, - options(nostack), - ); +macro_rules! define_syscall_fns{ + ($(pub fn $sys_fn:ident($a:ident $(,$b:ident $(,$c:ident $(,$d:ident $(,$e:ident $(,$f:ident $(,$g:ident)?)?)?)?)?)?) -> usize;)+) => { + $( + pub fn $sys_fn(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize, $($g: usize)?)?)?)?)?)?) -> usize { + #[cfg(target_arch = "x86_64")] + unsafe { + asm!( + "syscall", + inout("rax") $a, + $(in("rdi") $b, $(in("rsi") $c, $(in("rdx") $d, $(in("r10") $e, $(in("r8") $f, $(in("r9") $g,)?)?)?)?)?)? + out("rcx") _, + out("r11") _, + options(nostack), + ); - $a - } + $a + } - #[cfg(target_arch = "aarch64")] - unreachable!("aarch64 is not supported yet"); - } - )+ + #[cfg(target_arch = "aarch64")] + unreachable!("aarch64 is not supported yet"); + } + )+ + } } define_syscall_fns!( diff --git a/src/aero_syscall/src/time.rs b/src/aero_syscall/src/time.rs index 891ce835f21..0d7a41a3985 100644 --- a/src/aero_syscall/src/time.rs +++ b/src/aero_syscall/src/time.rs @@ -1,9 +1,32 @@ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . + +pub const ITIMER_REAL: usize = 0; +pub const ITIMER_VIRTUAL: usize = 1; +pub const ITIMER_PROF: usize = 2; + +#[derive(Default, PartialEq)] #[repr(C)] pub struct TimeVal { pub tv_sec: i64, pub tv_usec: i64, } +#[derive(Default, PartialEq)] #[repr(C)] pub struct ITimerVal { pub it_interval: TimeVal, // Interval for periodic timer diff --git a/src/uapi/src/drm.rs b/src/uapi/src/drm.rs index ca17055c8dd..a62adb9521f 100644 --- a/src/uapi/src/drm.rs +++ b/src/uapi/src/drm.rs @@ -1,29 +1,27 @@ -/* - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ +// Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. +// Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. +// Copyright (C) 2021-2022 The Aero Project Developers. +// +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice (including the next +// paragraph) shall be included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. use crate::ioctl; use core::ffi; diff --git a/src/uapi/src/ioctl.rs b/src/uapi/src/ioctl.rs index 9940b81b72b..a69c8b23da2 100644 --- a/src/uapi/src/ioctl.rs +++ b/src/uapi/src/ioctl.rs @@ -1,10 +1,8 @@ -/* - * The generic ioctl numbering scheme doesn't really enforce - * a type field. De facto, however, the top 8 bits of the lower 16 - * bits are indeed used as a type field, so we might just as well make - * this explicit here. Please be sure to use the decoding functions - * below from now on. - */ +// The generic ioctl numbering scheme doesn't really enforce +// a type field. De facto, however, the top 8 bits of the lower 16 +// bits are indeed used as a type field, so we might just as well make +// this explicit here. Please be sure to use the decoding functions +// below from now on. pub const IOC_NRBITS: usize = 8; pub const IOC_TYPEBITS: usize = 8; pub const IOC_SIZEBITS: usize = 14; @@ -25,12 +23,10 @@ pub const fn ioc(dir: usize, ty: usize, nr: usize, size: usize) -> usize { | ((size) << IOC_SIZESHIFT) } -/* - * Used to create numbers. - * - * NOTE: `iow` means userland is writing and kernel is reading. `ior` - * means userland is reading and kernel is writing. - */ +// Used to create numbers. +// +// NOTE: `iow` means userland is writing and kernel is reading. `ior` +// means userland is reading and kernel is writing. #[inline] pub const fn io(typ: usize, nr: usize) -> usize { ioc(IOC_NONE, typ, nr, 0) diff --git a/src/uapi/src/lib.rs b/src/uapi/src/lib.rs index 43250f515c9..8b510fb30c3 100644 --- a/src/uapi/src/lib.rs +++ b/src/uapi/src/lib.rs @@ -2,3 +2,4 @@ pub mod drm; pub mod ioctl; +pub mod pty; diff --git a/src/uapi/src/pty.rs b/src/uapi/src/pty.rs new file mode 100644 index 00000000000..fae22eb8955 --- /dev/null +++ b/src/uapi/src/pty.rs @@ -0,0 +1,4 @@ +use crate::ioctl; + +pub const TIOCGPTN: usize = ioctl::ior::('T' as usize, 0x30); +pub const TIOCSPTLCK: usize = ioctl::iow::('T' as usize, 0x31); diff --git a/tools/cargo-inject-patches.py b/tools/cargo-inject-patches.py index 2b5e4b8bd05..18be0cf7d05 100644 --- a/tools/cargo-inject-patches.py +++ b/tools/cargo-inject-patches.py @@ -1,39 +1,57 @@ +#!/usr/bin/env python3 # Copied over from https://github.com/managarm/bootstrap-managarm/scripts/cargo-inject-patches.py import argparse import os -import subprocess import pathlib +import subprocess patched_libs = { - 'libc': '0.2.93', - 'num_cpus': '1.13.0', - 'users': '0.11.0', + "backtrace": "0.3.64", + "calloop": "0.9.3", + "libc": "0.2.149", + "getrandom": "0.2.9", + "libloading": "0.7.3", + "mio": ["0.6.23", "0.8.3"], + "nix": "0.24.3", + "num_cpus": "1.15.0", + "users": "0.11.0", + "winit": "0.26.1", + "glutin": "0.28.0", + "glutin_glx_sys": "0.1.7", + "glutin_egl_sys": "0.1.5", + "shared_library": "0.1.9", + "rustix": "0.38.13" } -parser = argparse.ArgumentParser( - description='Inject patched Rust libraries into Cargo lockfiles') -parser.add_argument('manifest', type=pathlib.Path, help='path to Cargo.toml') +parser = argparse.ArgumentParser(description="Inject patched Rust libraries into Cargo lockfiles") +parser.add_argument("manifest", type=pathlib.Path, help="path to Cargo.toml") manifest = parser.parse_args().manifest # First, delete the existing lockfile to work around https://github.com/rust-lang/cargo/issues/9470 -lockfile = os.path.join(os.path.dirname(manifest), 'Cargo.lock') -if os.path.exists(lockfile): - print('cargo-inject-patches: workaround cargo bug by removing existing lockfile...') - os.remove(lockfile) +# lockfile = os.path.join(os.path.dirname(manifest), "Cargo.lock") +# if os.path.exists(lockfile): +# print("cargo-inject-patches: workaround cargo bug by removing existing lockfile...") +# os.remove(lockfile) + +for lib, versions in patched_libs.items(): + if not isinstance(versions, list): + versions = [versions] -for lib, version in patched_libs.items(): - cmd = [ - 'cargo', - 'update', - '--manifest-path', manifest, - '--package', lib, - '--precise', version - ] + for version in versions: + cmd = [ + "cargo", + "update", + "--manifest-path", + manifest, + "--package", + lib, + "--precise", + version, + ] - output = subprocess.run(cmd, capture_output=True) - if 'did not match any packages' in str(output.stderr): - print( - f'cargo-inject-patches: Injecting {lib} v{version} failed, patch not used') - else: - print(f'cargo-inject-patches: Injected {lib} v{version}') + output = subprocess.run(cmd) + if "did not match any packages" in str(output.stderr): + print(f"cargo-inject-patches: Injecting {lib} v{version} failed, patch not used") + else: + print(f"cargo-inject-patches: Injected {lib} v{version}") diff --git a/tools/deps.sh b/tools/deps.sh new file mode 100755 index 00000000000..ce93b7e7367 --- /dev/null +++ b/tools/deps.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# deps.sh +# dependency installer script +# +# note: should be replaced as part of build system rework + +set -e + +RED='\033[1;31m' +GREEN='\033[1;32m' +NC='\033[0m' # no colour + +function log_info() { echo -e "$PREFIX ${GREEN}info${NC}: $1"; } +function log_error() { echo -e "$PREFIX ${RED}error${NC}: $1"; } + +PREFIX='deps.sh>' + +PKGMAN='unknown' +PKGPREFIX='' +PKGINSTALL='' +PKGQUERY='' + +PARENTDIR=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) + +PLATFORM=$(uname) +DEPSDIR="$PARENTDIR/deps" +DEPSFILE="$DEPSDIR/deps_${PLATFORM,,}" + +. $DEPSFILE + +log_info "\`$PLATFORM\` system detected" +log_info "installing packages from \`$DEPSFILE\` with \`$PKGMAN\`..." + +if [[ !("$PLATFORM" == "Darwin") && ("$EUID" -ne 0) ]]; then + log_error "please run as root" + exit +fi + +for pkg in "${packages[@]}"; do + echo -n "installing $pkg... " + + # TODO: handle potential errors in installation commands + if [[ "$VERBOSE" == "true" ]]; then + install_package $pkg + else + install_package $pkg &>/dev/null + fi + + if query_package $pkg; then + echo -e "${GREEN}ok${NC}" + else + echo -e "${RED}FAILED${NC}" + fi +done + +log_info "completed" diff --git a/tools/deps/deps_darwin b/tools/deps/deps_darwin new file mode 100644 index 00000000000..f424eb39f09 --- /dev/null +++ b/tools/deps/deps_darwin @@ -0,0 +1,56 @@ +#!/usr/bin/bash + +PKGMAN='brew' + +# +# +# DEPENDENCIES BELOW ARE NOT IN Homebrew REPOS +# +# patch PREINSTALLED ON darwin/macOS +# tar PREINSTALLED ON darwin/macOS +# python-pip TODO: ALTERNATIVE INSTALL +# python-mako TODO: ALTERNATIVE INSTALL +packages=( + "bash" + "coreutils" + "make" + "gzip" + "binutils" + "gcc" + "git" + "subversion" + "mercurial" + "curl" + "wget" + "xz" + "nasm" + "mtools" + "meson" + "perl" + "m4" + "texinfo" + "groff" + "gettext" + "expat" + "bison" + "flex" + "help2man" + "openssl" + "gperf" + "rsync" + "libxslt" + "python" + "xcb-proto" + "xorriso" + "boost" + "cmake" +) + +function install_package() { brew install $1; } +function query_package() { + brew list | { + RESULT=$(grep -q $1); + cat > /dev/null; + return $RESULT; + } +} diff --git a/tools/deps/deps_linux b/tools/deps/deps_linux new file mode 100755 index 00000000000..4da9f86b8cb --- /dev/null +++ b/tools/deps/deps_linux @@ -0,0 +1,95 @@ +#!/usr/bin/bash + +if [ -x "$(command -v apt)" ]; then +PKGMAN="apt" + +packages=( + "autopoint" + "bash" + "binutils" + "bison" + "cmake" + "coreutils" + "curl" + "expat" + "flex" + "gcc" + "gettext" + "git" + "gperf" + "groff" + "gzip" + "help2man" + "libgmp-dev" + "m4" + "make" + "mercurial" + "meson" + "mtools" + "nasm" + "openssl" + "patch" + "perl" + "python3" + "python3-mako" + "python3-pip" + "rsync" + "subversion" + "tar" + "texinfo" + "wget" + "xcb-proto" + "xorriso" + "xsltproc" + "xz-utils" +) + +function install_package() { apt-get install -y $1; } +function query_package() { dpkg -l | grep -q $1; } +elif [ -x "$(command -v pacman)" ]; then # if [ -x "$(command -v apt)" ]; then +PKGMAN="pacman" + +packages=( + "bash" + "coreutils" + "make" + "patch" + "tar" + "gzip" + "binutils" + "gcc" + "git" + "subversion" + "mercurial" + "curl" + "wget" + "xz" + "nasm" + "mtools" + "meson" + "perl" + "m4" + "texinfo" + "groff" + "gettext" + "expat" + "bison" + "flex" + "help2man" + "openssl" + "gperf" + "rsync" + "libxslt" + "python" + "python-pip" + "python-mako" + "xcb-proto" + "libisoburn" + "boost-libs" + "cmake" + "itstool" +) + +function install_package() { pacman -S $1 --noconfirm; } +function query_package() { pacman -Q | grep -q $1; } +fi # elif [ -x "$(command -v pacman)" ]; then diff --git a/tools/gdb-debug-userland.py b/tools/gdb-debug-userland.py index 1383e0e66ac..8b16cc2e792 100755 --- a/tools/gdb-debug-userland.py +++ b/tools/gdb-debug-userland.py @@ -42,7 +42,7 @@ def wait_for_process(process): import gdb # Since GDB does not let us pass arguments to the script and we have a big - # brain, so we pass the arguments to the program as enviornment variables. + # brain, so we pass the arguments to the program as environment variables. program = os.getenv("AERO_DEBUG_USERLAND_PROGRAM") is_lib = os.environ.get("IS_LIB") == "yes" diff --git a/tools/mkimage.sh b/tools/mkimage.sh new file mode 100755 index 00000000000..e2d66af35f3 --- /dev/null +++ b/tools/mkimage.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +set -x -e + +ANSI_CLEAR="\033[0m" +ANSI_RED="\033[1;31m" +ANSI_BOLD="\033[1m" + +function warn() { + echo -e "${ANSI_RED}error${ANSI_CLEAR}: ${ANSI_BOLD}$1${ANSI_CLEAR}" +} + +function newest_file() { + local latest file + for file; do + [[ $file && $file -nt $latest ]] || latest=$file + done +} + +function has_newer_files_than() { + [[ "$(newest_file "$1"/*)" -nt "$(newest_file "$2" "$2"/*)" ]] +} + +# check if the packages directory is not newer than the system-root +if has_newer_files_than "./sysroot/packages" "./system/system-root"; then + warn "\`./sysroot/packages\` is newer than \`./sysroot/system-root\`, run \`xbstrap install --all\`" + exit 1 +fi + +# sync the sysroot +echo "sysroot: syncing base-files" +cp -r base-files/. sysroot/system-root/ + +IMAGE_PATH=build/disk.img + +# set $SUID_BINARY based on installed SUID binary +if command -v sudo; then + SUID_BINARY=$(which sudo) +else + echo "mkimage.sh: sudo not found, attempting to use opendoas" + SUID_BINARY=$(which doas) +fi + +# make the disk image +rm -rf $IMAGE_PATH +dd if=/dev/zero bs=1G count=0 seek=512 of=$IMAGE_PATH +parted -s $IMAGE_PATH mklabel gpt +parted -s $IMAGE_PATH mkpart primary 2048s 100% + +# ensure loop kernel module is enabled +if ! lsmod | grep -q 'loop'; then + echo 'mkimage.sh: `loop` kernel module not found, attempting to load' + $SUID_BINARY modprobe loop +fi + +$SUID_BINARY losetup -Pf --show $IMAGE_PATH > loopback_dev +$SUID_BINARY mkfs.ext2 `cat loopback_dev`p1 -I128 +rm -rf disk_image/ +mkdir disk_image +$SUID_BINARY mount `cat loopback_dev`p1 disk_image +$SUID_BINARY cp -r -v sysroot/system-root/. disk_image/ +pushd disk_image +$SUID_BINARY mkdir -p dev +$SUID_BINARY mkdir -p home +$SUID_BINARY mkdir -p tmp +$SUID_BINARY mkdir -p proc +$SUID_BINARY mkdir -p var +$SUID_BINARY mkdir -p mnt +popd +sync +$SUID_BINARY umount disk_image/ + +$SUID_BINARY losetup -d `cat loopback_dev` +sync + +rm -rf loopback_dev +rm -rf disk_image diff --git a/tools/rebuild-sysroot.sh b/tools/rebuild-sysroot.sh index 0c6a22e0980..428aeb2789b 100755 --- a/tools/rebuild-sysroot.sh +++ b/tools/rebuild-sysroot.sh @@ -17,9 +17,15 @@ # You should have received a copy of the GNU General Public License # along with Aero. If not, see . +set -x -e + SPATH=$(dirname $(readlink -f "$0")) AERO_PATH=$(realpath $SPATH/..) +# remove the build directory to ensure the build image +# is rebuilt. +rm -rf $AERO_PATH/build + if [ -z "$1" ]; then echo "Usage: $0 [] [--tool]" exit 1 diff --git a/userland/CMakeToolchain-x86_64.cmake b/userland/CMakeToolchain-x86_64.cmake new file mode 100644 index 00000000000..1e305c84a70 --- /dev/null +++ b/userland/CMakeToolchain-x86_64.cmake @@ -0,0 +1,16 @@ +set(CMAKE_SYSTEM_NAME Aero) + +set(CMAKE_FIND_ROOT_PATH /sysroot) + +set(CMAKE_C_COMPILER x86_64-aero-gcc) +set(CMAKE_CXX_COMPILER x86_64-aero-g++) + +# search for programs in the build host directories +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# for libraries and headers in the target directories +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# flags for shared libraries +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,") +set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1) diff --git a/userland/Cargo.lock b/userland/Cargo.lock deleted file mode 100644 index e4da3fb9b07..00000000000 --- a/userland/Cargo.lock +++ /dev/null @@ -1,505 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aero_ipc" -version = "0.1.0" -dependencies = [ - "aero_syscall", - "lazy_static", - "postcard", - "serde", - "spin 0.9.3", -] - -[[package]] -name = "aero_shell" -version = "0.1.0" -dependencies = [ - "aero_ipc", - "aero_syscall", - "libc 0.2.125", -] - -[[package]] -name = "aero_syscall" -version = "0.1.0" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "atomic-polyfill" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14bf7b4f565e5e717d7a7a65b2a05c0b8c96e4db636d6f780f03b15108cdd1b" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version 0.2.3", -] - -[[package]] -name = "bare-metal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" - -[[package]] -name = "bit_field" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cortex-m" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd20d4ac4aa86f4f75f239d59e542ef67de87cce2c282818dc6e84155d3ea126" -dependencies = [ - "bare-metal 0.2.5", - "bitfield", - "embedded-hal", - "volatile-register", -] - -[[package]] -name = "critical-section" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95da181745b56d4bd339530ec393508910c909c784e8962d15d722bacf0bcbcd" -dependencies = [ - "bare-metal 1.0.0", - "cfg-if", - "cortex-m", - "riscv", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc 0.2.126", - "wasi", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" -dependencies = [ - "ahash", -] - -[[package]] -name = "heapless" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065681e99f9ef7e0e813702a0326aedbcbbde7db5e55f097aedd1bf50b9dca43" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version 0.4.0", - "serde", - "spin 0.9.3", - "stable_deref_trait", -] - -[[package]] -name = "init" -version = "0.1.0" -dependencies = [ - "aero_syscall", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin 0.5.2", -] - -[[package]] -name = "libc" -version = "0.2.125" -source = "git+https://github.com/andy-Python-Programmer/libc#707daa9c11222ac2c3ac4d1ba23c96a21d2d633c" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.0.0", -] - -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - -[[package]] -name = "once_cell" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" - -[[package]] -name = "postcard" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25c0b0ae06fcffe600ad392aabfa535696c8973f2253d9ac83171924c58a858" -dependencies = [ - "heapless", - "postcard-cobs", - "serde", -] - -[[package]] -name = "postcard-cobs" -version = "0.1.5-pre" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c68cb38ed13fd7bc9dd5db8f165b7c8d9c1a315104083a2b10f11354c2af97f" - -[[package]] -name = "proc-macro2" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" - -[[package]] -name = "riscv" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6907ccdd7a31012b70faf2af85cd9e5ba97657cc3987c4f13f8e4d2c2a088aba" -dependencies = [ - "bare-metal 1.0.0", - "bit_field", - "riscv-target", -] - -[[package]] -name = "riscv-target" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.10", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "system_server" -version = "0.1.0" -dependencies = [ - "aero_ipc", - "aero_syscall", - "hashbrown", - "spin 0.9.3", -] - -[[package]] -name = "unicode-ident" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "utest" -version = "0.1.0" -dependencies = [ - "aero_ipc", - "aero_syscall", - "utest-proc", -] - -[[package]] -name = "utest-proc" -version = "0.1.0" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" -dependencies = [ - "vcell", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "window_server" -version = "0.1.0" -dependencies = [ - "aero_ipc", - "aero_syscall", - "hashbrown", - "spin 0.9.3", -] - -[[package]] -name = "window_test" -version = "0.1.0" -dependencies = [ - "aero_ipc", - "aero_syscall", -] diff --git a/userland/Cargo.toml b/userland/Cargo.toml deleted file mode 100644 index 1a52adcab02..00000000000 --- a/userland/Cargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[workspace] -members = ["apps/*", "servers/*"] - -[profile.release] -debug = true diff --git a/userland/Makefile b/userland/Makefile new file mode 100644 index 00000000000..e38cbe8ba90 --- /dev/null +++ b/userland/Makefile @@ -0,0 +1,44 @@ +.PHONY: all clean install + +override TARGET_DIR := target + +override SYSTRACE_DIR := apps/systrace +override SYSTRACE_TARGET := $(TARGET_DIR)/systrace + +override TEST_DIR := tests +override TEST_TARGET = $(TARGET_DIR)/utest + +override F_TARGET := $(TARGET_DIR)/f + +override INIT_DIR := init +override INIT_TARGET := $(TARGET_DIR)/init + +all: $(INIT_TARGET) $(SYSTRACE_TARGET) $(TEST_TARGET) $(F_TARGET) + +$(INIT_TARGET): $(INIT_DIR)/init.c + mkdir -p $(TARGET_DIR) + $(CC) -o $@ $^ + +$(SYSTRACE_TARGET): $(SYSTRACE_DIR) + mkdir -p $(TARGET_DIR) + cd $(SYSTRACE_DIR) && cargo build --release + cp $(SYSTRACE_DIR)/target/x86_64-unknown-aero/release/systrace $(SYSTRACE_TARGET) + +$(TEST_TARGET): $(TEST_DIR)/utest.cc + mkdir -p $(TARGET_DIR) + $(CXX) -o $@ $^ + +$(F_TARGET): $(TEST_DIR)/f.c + mkdir -p $(TARGET_DIR) + $(CC) -o $@ $^ + +clean: + rm -rf $(INIT_TARGET) + rm -rf $(SYSTRACE_TARGET) + +install: + install -d "$(DESTDIR)$(PREFIX)/bin" + install $(INIT_TARGET) "$(DESTDIR)$(PREFIX)/bin/" + install $(SYSTRACE_TARGET) "$(DESTDIR)$(PREFIX)/bin/" + install $(TEST_TARGET) "$(DESTDIR)$(PREFIX)/bin/" + install $(F_TARGET) "$(DESTDIR)$(PREFIX)/bin/" diff --git a/userland/apps/aero_shell/Cargo.toml b/userland/apps/aero_shell/Cargo.toml deleted file mode 100644 index 543df72bdaf..00000000000 --- a/userland/apps/aero_shell/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "aero_shell" -version = "0.1.0" -authors = ["Anhad Singh "] -edition = "2021" - -[dependencies] -aero_syscall = { path = "../../../src/aero_syscall" } -aero_ipc = { path = "../../libs/aero_ipc" } -libc = { git = "https://github.com/andy-Python-Programmer/libc" } diff --git a/userland/apps/aero_shell/src/main.rs b/userland/apps/aero_shell/src/main.rs deleted file mode 100644 index 52a084c2a3d..00000000000 --- a/userland/apps/aero_shell/src/main.rs +++ /dev/null @@ -1,464 +0,0 @@ -/* -* Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use std::sync::atomic::{AtomicU32, Ordering}; - -use std::error::Error; -use std::io::{BufRead, BufReader}; - -use std::fs::File; - -use std::fs; -use std::process; - -use aero_ipc::SystemService; -use aero_syscall::*; - -use std::io::Write; - -const MAGENTA_FG: &str = "\x1b[1;35m"; -const RESET: &str = "\x1b[0m"; -const UWUFETCH_LOGO: &str = r#" - ,---, - ' .' \ - / ; '. - : : \ - : | /\ \ - | : ' ;. : - | | ;/ \ \ - ' : | \ \ ,' - | | ' '--' - | : : - | | ,' - `--'' -"#; - -macro_rules! error { - ($($arg:tt)*) => { - std::print!("\x1b[1;31merror\x1b[0m: {}\n", format_args!($($arg)*)) - } -} - -static LAST_EXIT_CODE: AtomicU32 = AtomicU32::new(0); - -fn repl(history: &mut Vec) -> Result<(), SyscallError> { - let mut hostname_buf = [0; 64]; - let mut pwd_buffer = [0; 1024]; - let mut cmd_buffer = [0; 1024]; - - let hostname_len = sys_gethostname(&mut hostname_buf)?; - let hostname = unsafe { core::str::from_utf8_unchecked(&hostname_buf[0..hostname_len]) }; - let username = "root"; // TODO: Unhardcode this at some point :^) - - let pwd_length = sys_getcwd(&mut pwd_buffer)?; - let pwd = unsafe { core::str::from_utf8_unchecked(&pwd_buffer[0..pwd_length]) }; - - let mut stdout = std::io::stdout(); - - write!( - stdout, - "\x1b[1;32m{}@{}\x1b[0m:\x1b[1;34m{}\x1b[0m ", - username, hostname, pwd - ) - .unwrap(); - - stdout.flush().unwrap(); - - let cmd_length = sys_read(0, &mut cmd_buffer)?; - let cmd_string = unsafe { core::str::from_utf8_unchecked(&cmd_buffer[0..cmd_length]).trim() }; - - let mut args = cmd_string.split_whitespace(); - - if let Some(cmd) = args.next() { - history.push(cmd_string.to_string()); - - match cmd { - "echo" => { - let message = args.collect::>().join(" "); - let message = message.replace( - "$?", - LAST_EXIT_CODE.load(Ordering::SeqCst).to_string().as_str(), - ); - - println!("{}", message); - } - - "ls" => list_directory(args.next().unwrap_or(".")).unwrap(), - "pwd" => println!("{}", pwd), - "cd" => { - sys_chdir(args.next().unwrap_or(".."))?; - } - "mkdir" => match args.next() { - Some(path) => { - sys_mkdir(path)?; - } - None => error!("mkdir: missing operand"), - }, - "rmdir" => match args.next() { - Some(path) => { - sys_rmdir(path)?; - } - None => error!("rmdir: missing operand"), - }, - "exit" => match args.next() { - Some(status) => match status.parse::() { - Ok(exit_code) => sys_exit(exit_code), - Err(_) => error!("exit: invalid operand"), - }, - None => sys_exit(0), - }, - "cat" => cat_file(args.next()).unwrap(), - "clear" => print!("{esc}[2J{esc}[1;1H", esc = 27 as char), - "dmsg" => print_kernel_log().unwrap(), - "uwufetch" => uwufetch()?, - "uname" => uname()?, - "history" => { - for entry in history.iter() { - println!("{}", entry); - } - } - - "uwutest" => { - // TODO: Make a uwutest program that is executed by the kernel - // if the test kernel is built instead of randomly bloating the shell - // with tests :). - - // let fb = sys_open("/dev/fb", OpenFlags::O_RDWR)?; - - // let buffer = &[u32::MAX; (1024 * 768)]; - // let casted = buffer.as_ptr() as *mut u8; - // let casted = unsafe { core::slice::from_raw_parts(casted, (1024 * 768) as usize) }; - - // println!("writing to fb"); - // sys_write(fb, casted)?; - // sys_close(fb)?; - - uwutest()?; - } - - "pid" => { - println!("{}", sys_getpid()?); - } - - "uptime" => { - print!("{}", get_uptime()?); - } - - "sleep" => { - let duration = args.next().unwrap_or("0").parse::().unwrap_or(0); - let timespec = TimeSpec { - tv_sec: duration as isize, - tv_nsec: 0, - }; - - sys_sleep(×pec)?; - } - - "shutdown" => sys_shutdown(), - - "doom" => { - let child = sys_fork()?; - - if child == 0 { - let args = args.collect::>(); - let mut argv = Vec::new(); - - argv.push("/usr/bin/doomgeneric"); - - argv.extend(&["-iwad", "./doom1.wad"]); - argv.extend(args); - - let argv = argv.as_slice(); - - if sys_exec("/usr/bin/doomgeneric", argv, &["TERM=linux"]).is_err() { - println!("{}: command not found", cmd); - sys_exit(1); - } - } else { - // Wait for the child - let mut status = 0; - sys_waitpid(child, &mut status, 0)?; - - let exit_code = status & 0xff; - LAST_EXIT_CODE.store(exit_code, Ordering::SeqCst); - - if exit_code != 0 { - error!("{} exited with a non-zero status code: {} ", cmd, exit_code); - } - } - } - - _ => { - let mut args = args.collect::>(); - - // If the command ends with an `&`, then we have to run the command in the background. - let run_background = args.last().map(|&e| e == "&").unwrap_or(false); - - // Remove the `&` from the arguments array if present. - if run_background { - args.pop(); - } - - let child = sys_fork()?; - - if child == 0 { - let mut argv = Vec::new(); - - argv.push(cmd); - argv.extend(args); - - let argv = argv.as_slice(); - - match sys_exec( - cmd, - argv, - &[ - "TERM=linux", - // The `XDG_RUNTIME_DIR` enviornment variable tells the tells any program you - // run where to find a user-specific directory in which it can store small - // temporary files. - "XDG_RUNTIME_DIR=tmp", - "DISPLAY=:0", - ], - ) { - Ok(_) => core::unreachable!(), - Err(SyscallError::EISDIR) => error!("{}: is a directory", cmd), - Err(SyscallError::ENOENT) => error!("{}: command not found", cmd), - Err(err) => error!("{}: {:?}", cmd, err), - } - - sys_exit(0); - } else if !run_background { - // We are not running the command in the background, so wait for the child. - let mut status = 0; - sys_waitpid(child, &mut status, 0)?; - - let exit_code = status & 0xff; - LAST_EXIT_CODE.store(exit_code, Ordering::SeqCst); - - if exit_code != 0 { - error!("{} exited with a non-zero status code: {} ", cmd, exit_code); - } - } - } - } - } - - Ok(()) -} - -fn list_directory(path: &str) -> Result<(), Box> { - let rdir = fs::read_dir(path)?; - - for file in rdir { - let name = file?.file_name(); - let name_str = name.to_str().ok_or("ls: invalid filename")?; - - print!("{name_str} "); - } - - println!(); - Ok(()) -} - -fn cat_file(path: Option<&str>) -> Result<(), Box> { - let file = path - .map(|e| File::open(e)) - // On the `None` arm, we take input from stdin until we get interrupted. This is the - // behaviour of `cat` that comes with any modern Linux distro. - .unwrap_or_else(|| File::open("/dev/tty"))?; - - let mut reader = BufReader::new(file); - - loop { - let mut line = String::new(); - let size = reader.read_line(&mut line)?; - - // We have reached the end of the file. - if size == 0 { - break; - } - - print!("{line}"); - } - - println!(); - Ok(()) -} - -fn print_kernel_log() -> Result<(), Box> { - // dmsg is just a wrapper around `cat /dev/kmsg` - // TODO: Add colored output back :^) - - cat_file(Some("/dev/kmsg")) -} - -fn uwutest() -> Result<(), SyscallError> { - let my_pid = sys_getpid()?; - let ipc = SystemService::open(sys_ipc_discover_root()?); - - ipc.announce(my_pid, "TestServer") - .expect("Failed to announce"); - - println!( - "TestServer is at {}", - ipc.discover("TestServer").expect("Failed to discover") - ); - - Ok(()) -} - -fn get_uptime() -> Result { - let mut info = unsafe { core::mem::zeroed() }; - - sys_info(&mut info)?; - - let mut uptime = String::new(); - - let days = info.uptime / (3600 * 24); - let hours = info.uptime % (3600 * 24) / 3600; - let minutes = info.uptime % 3600 / 60; - let seconds = info.uptime % 60; - - if days > 0 { - uptime.push_str(&format!( - "{} day{}, ", - days, - if days == 1 { "" } else { "s" } - )); - } - - if hours > 0 { - uptime.push_str(&format!( - "{} hour{}, ", - hours, - if hours == 1 { "" } else { "s" }, - )); - } - - if minutes > 0 { - uptime.push_str(&format!( - "{} minute{}, ", - minutes, - if minutes == 1 { "" } else { "s" } - )); - } - - uptime.push_str(&format!( - "{} second{}", - seconds, - if seconds == 1 { "" } else { "s" } - )); - - Ok(uptime) -} - -fn uwufetch() -> Result<(), SyscallError> { - let print_prefix = |prefix| { - print!("{}{}{}: ", MAGENTA_FG, prefix, RESET); - }; - - let mut hostname_buf = [0; 64]; - - let hostname_len = sys_gethostname(&mut hostname_buf)?; - let hostname = unsafe { core::str::from_utf8_unchecked(&hostname_buf[0..hostname_len]) }; - let username = "root"; // TODO: Unhardcode this at some point :^) - - for (i, line) in UWUFETCH_LOGO.lines().skip(1).enumerate() { - print!(" {}{:<19}{}", MAGENTA_FG, line, RESET); - - if i == 1 { - println!("{}@{}", username, hostname); - } else if i == 2 { - println!("{}", "-".repeat(username.len() + hostname.len() + 1)); - } else if i == 3 { - print_prefix("OS"); - println!("Aero"); - } else if i == 4 { - let tty_fd = sys_open("/dev/tty", OpenFlags::O_RDONLY)?; - - let mut resolution = WinSize::default(); - sys_ioctl(tty_fd, TIOCGWINSZ, &mut resolution as *mut _ as usize)?; - - sys_close(tty_fd)?; - - print_prefix("Resolution"); - println!("{}x{}", resolution.ws_xpixel, resolution.ws_ypixel); - } else if i == 5 { - let mut uname_info = Utsname::default(); - - sys_uname(&mut uname_info)?; - - print_prefix("Kernel"); - println!( - "{} {} ({})", - uname_info.name(), - uname_info.version(), - uname_info.machine() - ); - } else if i == 6 { - print_prefix("Uptime"); - println!("{}", get_uptime()?); - } else { - println!(); - } - } - - Ok(()) -} - -fn uname() -> Result<(), SyscallError> { - let mut uname_info = Utsname::default(); - - sys_uname(&mut uname_info)?; - - println!( - "{} {} {} {} {}", - uname_info.name(), - uname_info.nodename(), - uname_info.release(), - uname_info.version(), - uname_info.machine() - ); - - Ok(()) -} - -fn handle_segmentation_fault(_fault: usize) { - error!("segmentation fault"); - process::exit(1); -} - -/// Sets the disposition of the signal number to handler. -fn install_sighandler(signum: libc::c_int, handler: fn(usize)) -> libc::sighandler_t { - unsafe { libc::signal(signum, handler as libc::sighandler_t) } -} - -fn main() { - // install all the necessary signal handlers. - install_sighandler(libc::SIGSEGV, handle_segmentation_fault); - - let mut history = vec![]; - - loop { - if let Err(error) = repl(&mut history) { - error!("{:?}", error); - } - } -} diff --git a/userland/apps/init/Cargo.toml b/userland/apps/init/Cargo.toml index 6b32449314a..3c879f68388 100644 --- a/userland/apps/init/Cargo.toml +++ b/userland/apps/init/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" [dependencies] aero_syscall = { path = "../../../src/aero_syscall" } +libc = { git = "https://github.com/Andy-Python-Programmer/libc" } diff --git a/userland/apps/init/src/main.rs b/userland/apps/init/src/main.rs index ac8a4d91a3a..ecbaef5d8c2 100644 --- a/userland/apps/init/src/main.rs +++ b/userland/apps/init/src/main.rs @@ -1,41 +1,77 @@ -/* -* Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2022 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use std::error::Error; -use std::fs::OpenOptions; +use std::fs::{File, OpenOptions}; +use std::os::fd::AsRawFd; use std::process::Command; -use std::mem; +const TTY_PATH: &str = "/dev/vtty"; +const DEV_NULL: &str = "/dev/null"; -const DEFAULT_SHELL_PATH: &str = "/usr/bin/bash"; -const TTY_PATH: &str = "/dev/tty"; +struct FileSet([File; N]); + +impl FileSet { + fn new(files: [File; N]) -> Self { + Self(files) + } + + fn remove_cloexec(&self) { + for file in self.0.iter() { + // By default rust automatically sets the close-on-exe flag to prevent + // leaking file descriptors. + // + // OpenOptions::custom_flags() only allows insertion of flags and are + // overwritten by the flags set by the standard library. So here, we + // need to manually update the flags after opening the file. + let fd = file.as_raw_fd(); + + unsafe { + assert!(libc::fcntl(fd, libc::F_SETFD, 0 /* flags */) == 0); + } + } + } +} fn main() -> Result<(), Box> { // Open the stdin, stdout and stderr file descriptors. - // - // mem::forget(): don't drop the object which in turn will close the - // file. - mem::forget(OpenOptions::new().read(true).open(TTY_PATH)?); // fd=0 for stdin - mem::forget(OpenOptions::new().write(true).open(TTY_PATH)?); // fd=1 for stdout - mem::forget(OpenOptions::new().write(true).open(TTY_PATH)?); // fd=2 for stderr - - Command::new(DEFAULT_SHELL_PATH).spawn()?; + let stdin = OpenOptions::new().read(true).open(TTY_PATH)?; // fd=0 + let stdout = OpenOptions::new().write(true).open(TTY_PATH)?; // fd=1 + let stderr = OpenOptions::new().write(true).open(TTY_PATH)?; // fd=2 + + { + let stdset = FileSet::new([stdin, stdout, stderr]); + stdset.remove_cloexec(); + + Command::new("dhcpd").spawn()?; + } + + // Swap the `/dev/tty` std{in,out,err} file descriptors with `/dev/null` to suppress the Xorg + // server logs. + let stdin = OpenOptions::new().read(true).open(DEV_NULL)?; // fd=0 + let stdout = OpenOptions::new().write(true).open(DEV_NULL)?; // fd=1 + let stderr = OpenOptions::new().write(true).open(DEV_NULL)?; // fd=2 + + let stdset = FileSet::new([stdin, stdout, stderr]); + stdset.remove_cloexec(); + + Command::new("startx") + .env("RUST_BACKTRACE", "full") + .spawn()?; Ok(()) } diff --git a/userland/apps/systrace/Cargo.toml b/userland/apps/systrace/Cargo.toml new file mode 100644 index 00000000000..c9865830a45 --- /dev/null +++ b/userland/apps/systrace/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "systrace" +version = "0.1.0" +edition = "2021" + +[dependencies] +aero_syscall = { path = "/base_dir/src/aero_syscall" } diff --git a/userland/apps/systrace/src/main.rs b/userland/apps/systrace/src/main.rs new file mode 100644 index 00000000000..c3c4cdbdb08 --- /dev/null +++ b/userland/apps/systrace/src/main.rs @@ -0,0 +1,16 @@ +use std::env; +use std::process::Command; + +use std::os::unix::process::CommandExt; + +use aero_syscall::syscall0; + +fn main() { + // [1..] to ignore the name of our binary. + let args = &env::args().collect::>()[1..]; + + syscall0(aero_syscall::prelude::SYS_TRACE); + + Command::new(&args[0]).args(&args[1..]).exec(); + unreachable!("systrace: failed to execute target process {args:?}") +} diff --git a/userland/apps/utest-proc/Cargo.toml b/userland/apps/utest-proc/Cargo.toml deleted file mode 100644 index 7443a34d2b8..00000000000 --- a/userland/apps/utest-proc/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "utest-proc" -version = "0.1.0" -edition = "2021" -authors = ["Anhad Singh "] - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "1.0.82", features = ["proc-macro", "full"] } -quote = "1.0.10" diff --git a/userland/apps/utest-proc/src/lib.rs b/userland/apps/utest-proc/src/lib.rs deleted file mode 100644 index 80683d16f5d..00000000000 --- a/userland/apps/utest-proc/src/lib.rs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -use proc_macro::TokenStream; -use syn::ItemFn; - -extern crate proc_macro; - -#[proc_macro_attribute] -pub fn test(_: TokenStream, input: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(input as ItemFn); - - let name = &input.sig.ident; - let vis = &input.vis; - let body = &input.block; - - let marker_name = quote::format_ident!("{}_func", name); - - let result = quote::quote! { - #[allow(warnings)] - #vis static #name: crate::Test = crate::Test { - func: #marker_name, - path: concat!(module_path!(), "::", stringify!(#name)) - }; - - fn #marker_name() -> Result<(), SyscallError> { - #body - } - }; - - result.into() -} diff --git a/userland/apps/utest/Cargo.toml b/userland/apps/utest/Cargo.toml deleted file mode 100644 index fd91d4036b9..00000000000 --- a/userland/apps/utest/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "utest" -version = "0.1.0" -edition = "2021" -authors = ["Anhad Singh "] - -[dependencies] -aero_syscall = { path = "../../../src/aero_syscall" } -aero_ipc = { path = "../../libs/aero_ipc" } -utest-proc = { path = "../utest-proc" } diff --git a/userland/apps/utest/src/main.rs b/userland/apps/utest/src/main.rs deleted file mode 100644 index db20abf6daa..00000000000 --- a/userland/apps/utest/src/main.rs +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ - -#![feature(naked_functions)] - -use core::sync::atomic::{AtomicUsize, Ordering}; - -use aero_syscall::signal::*; -use aero_syscall::*; - -mod mmap; - -pub struct Test<'a> { - path: &'a str, - func: fn() -> Result<(), SyscallError>, -} - -static TEST_FUNCTIONS: &[&'static Test<'static>] = &[ - // TODO: Why does clone process fail? - // &clone_process, - &sysenter_test, - &rpc_test, - &forked_pipe, - &signal_handler, - &dup_fds, - &dup2_redirect_stdout, - &fcntl_get_set_fdflags, - // mmap tests: - &mmap::zero_sized_mapping, -]; - -fn main() { - sys_open("/dev/tty", OpenFlags::O_RDONLY).expect("Failed to open stdin"); - sys_open("/dev/tty", OpenFlags::O_WRONLY).expect("Failed to open stdout"); - sys_open("/dev/tty", OpenFlags::O_WRONLY).expect("Failed to open stderr"); - - println!("running {} tests", TEST_FUNCTIONS.len()); - - for test_function in TEST_FUNCTIONS { - (test_function.func)().unwrap(); - println!("test {} ... \x1b[1;32mok\x1b[0m", test_function.path); - } -} - -#[utest_proc::test] -fn fcntl_get_set_fdflags() -> Result<(), SyscallError> { - let fd = sys_open("/dev/tty", OpenFlags::O_RDONLY)?; - let flags = prelude::FdFlags::CLOEXEC; - - sys_fcntl(fd, prelude::F_SETFD, flags.bits())?; - let fd_flags = sys_fcntl(fd, prelude::F_GETFD, 0)?; - - core::assert_eq!(fd_flags, flags.bits()); - - sys_close(fd)?; - Ok(()) -} - -#[utest_proc::test] -fn dup2_redirect_stdout() -> Result<(), SyscallError> { - let utest_fd = sys_open("utest.txt", OpenFlags::O_WRONLY | OpenFlags::O_CREAT)?; - - // We set the new_fd to the file descriptor of stdout (i.e. 1) - sys_dup2(utest_fd, 1, OpenFlags::O_WRONLY)?; - - // Now if we write to stdout, it will be written to utest.txt - println!("yes"); - - sys_seek(utest_fd, 0, SeekWhence::SeekSet)?; - - let mut content = [0; 3]; - sys_read(utest_fd, &mut content)?; - - core::assert_eq!(&content, b"yes"); - - sys_unlink(AT_FDCWD as usize, "utest.txt", OpenFlags::empty())?; - sys_close(utest_fd)?; - - // Restore the actual stdout. - let tty_fd = sys_open("/dev/tty", OpenFlags::O_WRONLY)?; - sys_dup2(tty_fd, 1, OpenFlags::O_WRONLY)?; - - Ok(()) -} - -#[utest_proc::test] -fn dup_fds() -> Result<(), SyscallError> { - let utest_fd = sys_open("utest.txt", OpenFlags::O_WRONLY | OpenFlags::O_CREAT)?; - - // dup() will create a copy of the utest fd as cutest_fd then both can - // be used interchangeably. - let cutest_fd = sys_dup(utest_fd, OpenFlags::O_RDWR)?; - - sys_write(utest_fd, b"testing ")?; - sys_write(cutest_fd, b"dup...\n")?; - - sys_seek(utest_fd, 0, SeekWhence::SeekSet)?; - - let mut content = [0; 15]; - sys_read(utest_fd, &mut content)?; - - core::assert_eq!(&content, b"testing dup...\n"); - - sys_unlink(AT_FDCWD as usize, "utest.txt", OpenFlags::empty())?; - - // Close all of the fds. - sys_close(utest_fd)?; - sys_close(cutest_fd)?; - - Ok(()) -} - -#[utest_proc::test] -fn signal_handler() -> Result<(), SyscallError> { - let child = sys_fork()?; - - // We perform the test in a forked process since then we dont - // have to worry about restoring the signal handlers. - if child == 0 { - let mut pipe = [0usize; 2]; - sys_pipe(&mut pipe, OpenFlags::empty())?; - - static PIPE_WRITE: AtomicUsize = AtomicUsize::new(0); - PIPE_WRITE.store(pipe[1], Ordering::SeqCst); - - fn handle_segmentation_fault(fault: usize) { - core::assert_eq!(fault, 11); - - let pfd = PIPE_WRITE.load(Ordering::SeqCst); - - // Dont worry about closing the file descriptors since they will - // be auto closed by the parent. - sys_write(pfd, b"yes").expect("failed to write to the pipe"); - sys_exit(0); - } - - // Install the signal handler. - let handler = SignalHandler::Handle(handle_segmentation_fault); - let sigaction = SigAction::new(handler, 0, SignalFlags::empty()); - - sys_sigaction(SIGSEGV, Some(&sigaction), None) - .expect("failed to install the segmentation fault handler"); - - // On fork the signal handler will be copied over to the child process. - let child = sys_fork()?; - - if child == 0 { - // Create a traditional page fault :^) - unsafe { - *(0xcafebabe as *mut usize) = 69; - } - } else { - let mut buffer = [0; 3]; - sys_read(pipe[0], &mut buffer)?; - - core::assert_eq!(&buffer, b"yes"); - } - - // Close the pipe - sys_close(pipe[0])?; - sys_close(pipe[1])?; - - sys_exit(0) - } else { - let mut status = 0; - sys_waitpid(child, &mut status, 0)?; - } - - Ok(()) -} - -#[utest_proc::test] -fn forked_pipe() -> Result<(), SyscallError> { - let mut pipe = [0usize; 2]; - sys_pipe(&mut pipe, OpenFlags::empty())?; - - let child = sys_fork()?; - - if child == 0 { - sys_close(pipe[0])?; // close the read end - - sys_write(pipe[1], b"Hello, World!")?; - - sys_close(pipe[1])?; // close the write end - sys_exit(0) - } else { - let mut status = 0; - sys_waitpid(child, &mut status, 0)?; - - sys_close(pipe[1])?; // close the write end - - let mut buffer = [0; 13]; - sys_read(pipe[0], &mut buffer)?; - - core::assert_eq!(&buffer, b"Hello, World!"); - - sys_close(pipe[0])?; // close the read end - } - - Ok(()) -} - -// Emulates how mlibc under the hood does clone() -#[utest_proc::test] -fn clone_process() -> Result<(), SyscallError> { - const STACK_SIZE: usize = 4096; - - #[naked] - unsafe extern "C" fn cloned_process_start() { - core::arch::asm!( - " - pop rdi - pop rsi - pop rdx - call cloned_process_trampoline - ", - options(noreturn) - ); - } - - #[no_mangle] - extern "C" fn cloned_process_trampoline(func: usize, arg: usize, tcb: usize) { - core::assert_eq!(tcb, 0xcafebabe); - core::assert_eq!(arg, 0xbabecafe); - - let ptr = func as *const (); - let code: extern "C" fn() = unsafe { core::mem::transmute(ptr) }; - - (code)(); - sys_exit(0); - } - - extern "C" fn cloned_process() { - println!("Hello, World from cloned process!"); - } - - // Allocate the stack for the child process. - let stack = sys_mmap( - 0, - STACK_SIZE, - MMapProt::PROT_READ | MMapProt::PROT_WRITE, - MMapFlags::MAP_PRIVATE | MMapFlags::MAP_ANONYOMUS, - -1isize as usize, - 0, - )?; - - let stack_top = stack + STACK_SIZE; - let mut stack_ptr = stack_top as *mut usize; - - // Prepare the stack for the child process. - unsafe { - *stack_ptr = 0xcafebabe; // TCB pointer - - stack_ptr = stack_ptr.sub(1); - *stack_ptr = 0xbabecafe; // User argument - - stack_ptr = stack_ptr.sub(1); - *stack_ptr = cloned_process as usize; // Inner function - } - - // Create the child process. - let child = sys_clone(cloned_process_start as usize, stack_ptr as usize)?; - - let mut status = 0; - sys_waitpid(child, &mut status, 0)?; - - // Free the allocated stack. - sys_munmap(stack, STACK_SIZE)?; - - let exit_code = status & 0xff; - - if exit_code != 0 { - core::panic!("child exited with a non-zero status code: {}", exit_code); - } - - Ok(()) -} - -aero_ipc::ipc! { - trait Hello { - fn hello(favorite_number: i32) -> (); - } -} - -struct HelloServer; - -impl Hello::Server for HelloServer { - fn hello(&self, favnum: i32) { - println!("hey: {}", favnum); - } -} - -#[utest_proc::test] -fn rpc_test() -> Result<(), SyscallError> { - aero_ipc::listen(Hello::handler(HelloServer {})); - let c = Hello::open(sys_getpid().unwrap()); - c.hello(3); - - Ok(()) -} - -#[utest_proc::test] -fn sysenter_test() -> Result<(), SyscallError> { - let pid = sys_fork()?; - - if pid == 0 { - unsafe { - core::arch::asm! { - "sysenter", - in("rcx") 0xf0f0usize << 48, - in("r11") 0x0f0fusize << 48, - } - } - - core::unreachable!(); - } else { - let mut status = 0; - sys_waitpid(pid, &mut status, 0)?; - } - - let msg = "sysenter works!\n"; - let ptr = msg.as_ptr(); - let len = msg.len(); - - unsafe { - core::arch::asm! { - " - mov r11, rsp - lea rcx, [rip + 1f] - sysenter - 1: - ", - in("rax") consts::SYS_WRITE, - in("rdi") 1, - in("rsi") ptr, - inout("rdx") len => _, - out("r11") _, - out("rcx") _, - } - } - - Ok(()) -} diff --git a/userland/apps/utest/src/mmap.rs b/userland/apps/utest/src/mmap.rs deleted file mode 100644 index 49c9eb0abaf..00000000000 --- a/userland/apps/utest/src/mmap.rs +++ /dev/null @@ -1,18 +0,0 @@ -use aero_syscall::*; - -/// Assert that the `mmap` syscall bails out when you provide `0` as the -/// size of the mapping. -#[utest_proc::test] -pub fn zero_sized_mapping() -> Result { - let result = sys_mmap( - 0, - 0, - MMapProt::PROT_READ, - MMapFlags::MAP_ANONYOMUS | MMapFlags::MAP_PRIVATE, - -1isize as usize, - 0, - ); - - core::assert_eq!(result, Err(SyscallError::EFAULT)); - Ok(()) -} diff --git a/userland/apps/window_test/src/main.rs b/userland/apps/window_test/src/main.rs index 6b381df06d1..9a7496f9f34 100644 --- a/userland/apps/window_test/src/main.rs +++ b/userland/apps/window_test/src/main.rs @@ -1,24 +1,22 @@ -/* -* Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use aero_ipc::{SystemService, WindowService}; -use aero_syscall::*; +use aero_syscall::{sys_ipc_discover_root, SyscallError}; fn discover_service(name: &str) -> Result { let root_pid = sys_ipc_discover_root()?; diff --git a/userland/client.c b/userland/client.c deleted file mode 100644 index 7b0d7c9a072..00000000000 --- a/userland/client.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define SOCK_PATH "test.sock" - -int main() { - // Create the socket. - int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - - // Check for any errors during the creation. - if (sockfd < 0) { - perror("socket"); - return 1; - } - - struct sockaddr_un addr = {.sun_family = AF_UNIX}; - strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1); - - if (connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == - -1) { - perror("connect"); - return -1; - } - - struct iovec iov[1]; - - iov[0].iov_base = "Hello, world!\n"; - iov[0].iov_len = strlen(iov[0].iov_base); - - writev(sockfd, iov, 1); - close(sockfd); -} \ No newline at end of file diff --git a/userland/cross-file.ini b/userland/cross-file.ini index 61aaa230496..08d220581b6 100644 --- a/userland/cross-file.ini +++ b/userland/cross-file.ini @@ -1,13 +1,14 @@ -[binaries] -c = 'x86_64-aero-gcc' -cpp = 'x86_64-aero-g++' -ar = 'x86_64-aero-ar' -strip = 'x86_64-aero-strip' -ld = 'x86_64-aero-ld' -pkgconfig = 'x86_64-aero-pkg-config' - -[host_machine] -system = 'aero' -cpu_family = 'x86_64' -cpu = 'x86_64' -endian = 'little' +[binaries] +c = 'x86_64-aero-gcc' +cpp = 'x86_64-aero-g++' +ar = 'x86_64-aero-ar' +strip = 'x86_64-aero-strip' +ld = 'x86_64-aero-ld' +pkgconfig = 'x86_64-aero-pkg-config' +llvm-config = '/base_dir/build-support/cross-llvm-config' + +[host_machine] +system = 'aero' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/userland/init/init.c b/userland/init/init.c new file mode 100644 index 00000000000..aaee4abff9d --- /dev/null +++ b/userland/init/init.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include + +int main() { + int fd_stdin = open("/dev/vtty", O_RDONLY); + int fd_stdout = open("/dev/vtty", O_WRONLY); + int fd_stderr = open("/dev/vtty", O_WRONLY); + + printf("Hello world\n"); + + setenv("TERM", "linux", 1); + setenv("USER", "root", 1); + setenv("PATH", "/usr/local/bin:/usr/bin", 1); + setenv("HOME", "/home/aero", 1); + + int pid = fork(); + + if (!pid) { + char *args[] = {"/usr/bin/bash", "--login", NULL}; + chdir(getenv("HOME")); + execvp("/usr/bin/bash", args); + } else { + int status; + waitpid(pid, &status, 0); + } + + return 0; +} diff --git a/userland/libs/aero_ipc/src/lib.rs b/userland/libs/aero_ipc/src/lib.rs index ac8ab22fafa..5aff25713b6 100644 --- a/userland/libs/aero_ipc/src/lib.rs +++ b/userland/libs/aero_ipc/src/lib.rs @@ -1,21 +1,19 @@ -/* - * Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2022 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . #![feature(decl_macro)] mod interfaces; @@ -36,7 +34,7 @@ pub trait MessageHandler: Send + Sync { fn handle(&mut self, src: usize, msg: &[u8]) -> Result>, ()>; } -/// A MessageTransport allows for high-level IPC exchanges over the IPC interfce. +/// A MessageTransport allows for high-level IPC exchanges over the IPC interface. /// It also handles the allocation of request identifiers. pub trait MessageTransport { fn alloc_id() -> usize; @@ -44,20 +42,21 @@ pub trait MessageTransport { fn exchange(meta: usize, mid: usize, data: &[u8]) -> Vec; } -/// A SendRecieveTransport transfers messages by using the IPC system calls. -pub struct SendRecieveTransport; +/// A SendReceiveTransport transfers messages by using the IPC system calls. +pub struct SendReceiveTransport; // trust me, this seed is fine static IDALLOC: AtomicUsize = AtomicUsize::new(0xde73_ce13_600f_e4e9); -impl MessageTransport for SendRecieveTransport { +impl MessageTransport for SendReceiveTransport { fn alloc_id() -> usize { let value = IDALLOC.fetch_add(1, Ordering::SeqCst); // a small attempt at seed obfuscation IDALLOC.fetch_xor(value << 13, Ordering::SeqCst); IDALLOC.fetch_xor(value >> 7, Ordering::SeqCst); IDALLOC.fetch_xor(value << 17, Ordering::SeqCst); - return IDALLOC.fetch_add(1, Ordering::SeqCst) >> 3; + + IDALLOC.fetch_add(1, Ordering::SeqCst) >> 3 } fn free_id(_: usize) {} @@ -65,29 +64,27 @@ impl MessageTransport for SendRecieveTransport { fn exchange(meta: usize, mid: usize, msg: &[u8]) -> Vec { // send the data sys_ipc_send(meta, msg).expect("exchange failed: request failed!"); - // now wait for a repsonse + // now wait for a response loop { // get a response let rx = service_with_response_finding(); - match rx { - // if we got a response, - Some((srcpid, mut msg)) => { - // and the response has the correct message ID... - let mut deser = postcard::Deserializer::from_bytes(&msg); - let msgid = usize::deserialize(&mut deser) - .expect("message ID not present in the message!"); - if msgid == (mid << 1) | 1 && meta == srcpid { - // return the message contents! - return msg.split_off(core::mem::size_of::()); - } + + // if we got a response + if let Some((srcpid, mut msg)) = rx { + // and the response has the correct message ID... + let mut deser = postcard::Deserializer::from_bytes(&msg); + let msgid = + usize::deserialize(&mut deser).expect("message ID not present in the message!"); + if msgid == (mid << 1) | 1 && meta == srcpid { + // return the message contents! + return msg.split_off(core::mem::size_of::()); } - None => {} } } } } -/// The IPC inteface macro +/// The IPC interface macro /// /// You can create interfaces like this: /// ```no_run @@ -98,7 +95,7 @@ impl MessageTransport for SendRecieveTransport { /// ``` /// /// Then, Hello::Client is the client interface, Hello::Server is the server -/// inteface and Hello::handler instantiates a MessageHandler that can be added +/// interface and Hello::handler instantiates a MessageHandler that can be added /// to the listening pool. #[macro_export] macro_rules! ipc { @@ -133,7 +130,7 @@ macro_rules! ipc { )* } - pub fn open(pid: usize) -> Client<$crate::SendRecieveTransport> { + pub fn open(pid: usize) -> Client<$crate::SendReceiveTransport> { Client { pid, phantom: ::core::marker::PhantomData{} } } @@ -154,7 +151,7 @@ macro_rules! ipc { use serde::Deserialize; let mut deser = postcard::Deserializer::from_bytes(msg); - // TODO(pitust): cache this in the recieve part of the handler + // TODO(pitust): cache this in the receive part of the handler //? i don't think it would help *that* much though let msgid: usize = usize::deserialize(&mut deser).or_else(|_e| { println!("\x1b[31;1merr\x1b[0m message id failed to deserialize!"); @@ -209,7 +206,7 @@ pub fn handle_request(src: usize, msg: &[u8]) -> Option> { if (msg[0] & 1) == 1 { println!( - "\x1b[32;1mwarn\x1b[0m recieved random response from {}!", + "\x1b[32;1mwarn\x1b[0m received random response from {}!", src ); return None; @@ -233,7 +230,7 @@ pub fn handle_request(src: usize, msg: &[u8]) -> Option> { fn service_with_response_finding() -> Option<(usize, Vec)> { let mut src: usize = 0; - let mut arena = RX_ARENA.try_lock().expect("recieve arena is locked!"); + let mut arena = RX_ARENA.try_lock().expect("receive arena is locked!"); let msg = sys_ipc_recv(&mut src, arena.as_mut(), true).expect("sys_ipc_recv failed!"); // if it's a response @@ -253,14 +250,11 @@ pub fn service_request() { let mut src: usize = 0; let mut arena = RX_ARENA .try_lock() - .expect("service_request: recieve arena is locked!"); + .expect("service_request: receive arena is locked!"); let msg = sys_ipc_recv(&mut src, arena.as_mut(), true).expect("sys_ipc_recv failed!"); - match handle_request(src, msg) { - Some(data) => { - sys_ipc_send(src, &data).expect("sys_ipc_send failed, reply dropped!"); - } - _ => {} + if let Some(data) = handle_request(src, msg) { + sys_ipc_send(src, &data).expect("sys_ipc_send failed, reply dropped!"); } } diff --git a/userland/memory_stress.c b/userland/memory_stress.c new file mode 100644 index 00000000000..1493a914bb5 --- /dev/null +++ b/userland/memory_stress.c @@ -0,0 +1,43 @@ +// File: ../../../bundled/mlibc/subprojects/frigg/include/frg/slab.hpp:441: +// +// Assertion '!"slab_pool corruption. Possible write to unallocated object"' +// failed! +// +// Hypothesis: I observed that the error only happens in alacritty when the +// memory is under stress and in a secondary thread. So, it is +// likely an issue with how MLIBC locks the slab_pool or maybe +// something related to the futex implementation (but its likely +// not because other people using MLIBC are experiencing the same +// issue). +// +// "Congratulations! You've ran into the same damn bug that stopped chromium and +// webkitgtk join the crying club" - Dennis + +/* +G'day mate! As a bloody good programmer from down under, I'm bloody brilliant at +debugging even the most complex memory corruption issues. Recently, I used a +tool, ASAN, to identify the source of the corruption, and then I used my +bloody mad skills with a debugger like GDB to pinpoint the exact location of the +problem in the program's memory. I was able to quickly and efficiently fix the +issue, and now the program runs smoothly without any bloody memory corruption +errors. I'm bloody proud of my skills and the positive impact they have on the +programs I work on. +*/ + +#include +#include +#include + +void *fuck_around(void *arg) { + while (true) { + int *a = malloc(69); + *a = 69; + free(a); + } + return NULL; +} + +int main() { + pthread_t balls; + pthread_create(&balls, NULL, fuck_around, NULL); +} \ No newline at end of file diff --git a/userland/server.c b/userland/server.c deleted file mode 100644 index dc27ab64553..00000000000 --- a/userland/server.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define SOCK_PATH "test.sock" -#define BACK_LOG 69 - -int main() { - // Create the socket. - int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - - // Check for any errors during the creation. - if (sockfd < 0) { - perror("socket"); - return 1; - } - - struct sockaddr_un addr = {.sun_family = AF_UNIX}; - strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1); - - // Bind the socket to the address. - if (bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == - -1) { - perror("bind"); - return 1; - } - - // Listen for new connections. - if (listen(sockfd, BACK_LOG) == -1) { - perror("listen"); - return -1; - } - - for (;;) { - printf("Listening for a connection...\n"); - int con_fd = accept(sockfd, NULL, NULL); - - // Check for any errors during the connection. - if (con_fd < 0) { - perror("accept"); - return -1; - } - - printf("Accepted socket! (fd=%d)\n", con_fd); - - char buffer[4096]; - - struct iovec iov = { - .iov_base = &buffer, - .iov_len = sizeof(buffer), - }; - - struct msghdr msg = {.msg_iov = &iov, .msg_iovlen = 1}; - - int count = recvmsg(con_fd, &msg, 0); - if (count < 0) { - perror("recvmsg"); - return -1; - } - - printf("Received %d bytes: %s\n", count, buffer); - - if (close(con_fd) == -1) { - perror("close"); - return -1; - } - } -} \ No newline at end of file diff --git a/userland/servers/system_server/Cargo.toml b/userland/servers/system_server/Cargo.toml index 47545079c1b..b875cdaa3e7 100644 --- a/userland/servers/system_server/Cargo.toml +++ b/userland/servers/system_server/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] hashbrown = "0.12.0" -spin = "0.9.2" +spin = "0.9.8" aero_syscall = { path = "../../../src/aero_syscall" } aero_ipc = { path = "../../libs/aero_ipc" } diff --git a/userland/servers/system_server/src/main.rs b/userland/servers/system_server/src/main.rs index f78189abc95..54ad8378cc4 100644 --- a/userland/servers/system_server/src/main.rs +++ b/userland/servers/system_server/src/main.rs @@ -1,31 +1,30 @@ -/* -* Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use std::error::Error; use std::process::Command; use aero_ipc::{SystemService, SystemServiceError, SystemServiceResult}; use aero_syscall::*; -use hashbrown::{hash_map::Entry, HashMap}; +use hashbrown::hash_map::Entry; +use hashbrown::HashMap; use spin::RwLock; -fn main() -> Result<(), Box> { +fn main() -> core::result::Result<(), Box> { sys_ipc_become_root().unwrap(); aero_ipc::listen(SystemService::handler(SystemServer::new())); @@ -68,7 +67,7 @@ impl SystemService::Server for SystemServer { self.services .read() .get(&name) - .map(|pid| *pid) + .copied() .ok_or(SystemServiceError::NotFound) } } diff --git a/userland/servers/window_server/Cargo.toml b/userland/servers/window_server/Cargo.toml index e934c6b580e..9370d4d6585 100644 --- a/userland/servers/window_server/Cargo.toml +++ b/userland/servers/window_server/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] hashbrown = "0.12.0" -spin = "0.9.2" +spin = "0.9.8" aero_syscall = { path = "../../../src/aero_syscall" } aero_ipc = { path = "../../libs/aero_ipc" } +libc = { git = "https://github.com/Andy-Python-Programmer/libc" } diff --git a/userland/servers/window_server/src/main.rs b/userland/servers/window_server/src/main.rs index 85cd076db57..4f7d385e42e 100644 --- a/userland/servers/window_server/src/main.rs +++ b/userland/servers/window_server/src/main.rs @@ -1,27 +1,25 @@ -/* -* Copyright (C) 2021-2022 The Aero Project Developers. - * - * This file is part of The Aero Project. - * - * Aero 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 of the License, or - * (at your option) any later version. - * - * Aero 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. - * - * You should have received a copy of the GNU General Public License - * along with Aero. If not, see . - */ +// Copyright (C) 2021-2024 The Aero Project Developers. +// +// This file is part of The Aero Project. +// +// Aero 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 of the License, or +// (at your option) any later version. +// +// Aero 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. +// +// You should have received a copy of the GNU General Public License +// along with Aero. If not, see . use aero_ipc::{SystemService, WindowService}; -use aero_syscall::*; +use aero_syscall::sys_ipc_discover_root; fn main() { - let self_pid = sys_getpid().unwrap(); + let self_pid = unsafe { libc::getpid() as usize }; let ipc_root = sys_ipc_discover_root().unwrap(); let system_client = SystemService::open(ipc_root); diff --git a/userland/tests/f.c b/userland/tests/f.c new file mode 100644 index 00000000000..b96bfc81526 --- /dev/null +++ b/userland/tests/f.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include + +#define INITIAL_MSG "Hello, world!" +#define MSG_LEN (sizeof(INITIAL_MSG) - 1) + +#define NEXT_MSG "Bye, world!" + +int main() { + int fd = open("/tmp/shared_file", O_CREAT | O_RDWR, 0644); + write(fd, INITIAL_MSG, MSG_LEN); + + char *p = mmap(NULL, MSG_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + pid_t pid = fork(); + + if (!pid) { + strncpy(p, NEXT_MSG, MSG_LEN); + return EXIT_SUCCESS; + } + + int wstatus; + waitpid(pid, &wstatus, 0); + assert(WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == EXIT_SUCCESS); + + // ensure changes presist across processes + assert(!strncmp(p, NEXT_MSG, MSG_LEN)); + munmap(p, MSG_LEN); + + // synchronize mapped region with its underlying file + // msync(p, MSG_LEN, MS_SYNC); + + // ensure changes presist in the file + char buf[MSG_LEN]; + lseek(fd, 0, SEEK_SET); + read(fd, buf, MSG_LEN); + assert(!strncmp(buf, NEXT_MSG, MSG_LEN)); + + // cleanup + close(fd); + unlink("/tmp/shared_file"); + return EXIT_SUCCESS; +} diff --git a/userland/tests/utest.cc b/userland/tests/utest.cc new file mode 100644 index 00000000000..156ac20c6ca --- /dev/null +++ b/userland/tests/utest.cc @@ -0,0 +1,770 @@ +// clang-format off +// +// xbstrap runtool host-gcc -- x86_64-aero-g++ ../userland/tests/test.cc -o system-root/torture + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__aero__) +#include +#elif defined(__linux__) +#include +#else +#error "unknown platform" +#endif + +#define NAMED_PATH "/tmp/sockname" + +#define DEFINE_TEST(s, f) static test_case test_##s{#s, f}; + +struct abstract_test_case { +private: + static void register_case(abstract_test_case *tcp); + +public: + abstract_test_case(const char *name) : name_{name} { register_case(this); } + + abstract_test_case(const abstract_test_case &) = delete; + + virtual ~abstract_test_case() = default; + + abstract_test_case &operator=(const abstract_test_case &) = delete; + + const char *name() { return name_; } + + virtual void run() = 0; + +private: + const char *name_; +}; + +template struct test_case : abstract_test_case { + test_case(const char *name, F functor) + : abstract_test_case{name}, functor_{std::move(functor)} {} + + void run() override { functor_(); } + +private: + F functor_; +}; + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) + +#define log_error(M, ...) \ + fprintf(stderr, "[ERROR] %s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#define assertf(A, M, ...) \ + if (!(A)) { \ + log_error(M, ##__VA_ARGS__); \ + assert(A); \ + } + + +#define PAGE_SIZE 4096 + +void enable_systrace() { +#define SYS_TRACE 71 + long ret; + asm volatile("syscall" : "=a"(ret) : "a"(SYS_TRACE) : "rcx", "r11", "memory"); +} + +#define assert_errno(fail_func, expr) ((void)(((expr) ? 1 : 0) || (assert_errno_fail(fail_func, #expr, __FILE__, __PRETTY_FUNCTION__, __LINE__), 0))) + +inline void assert_errno_fail(const char *fail_func, const char *expr, + const char *file, const char *func, int line) { + int err = errno; + fprintf(stderr, "In function %s, file %s:%d: Function %s failed with error '%s'; failing assertion: '%s'\n", + func, file, line, fail_func, strerror(err), expr); + abort(); + __builtin_unreachable(); +} + +DEFINE_TEST(unix_getname, ([] { + int server_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(server_fd == -1) + assert(!"server socket() failed"); + + struct sockaddr_un server_addr; + memset(&server_addr, 0, sizeof(struct sockaddr_un)); + server_addr.sun_family = AF_UNIX; + strncpy(server_addr.sun_path, NAMED_PATH, sizeof(server_addr.sun_path) - 1); + + if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un))) + assert(!"bind() failed"); + if(listen(server_fd, 50)) + assert(!"listen() failed"); + + pid_t child = fork(); + if(!child) { + int client_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(client_fd == -1) + assert(!"client socket() failed"); + if(connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un))) + assert(!"connect() to server failed"); + + char buf[1]; + if (recv(client_fd, buf, 1, 0) < 0) + assert(!"recv() failed"); + exit(0); + } else { + int peer_fd = accept(server_fd, nullptr, nullptr); + if(peer_fd == -1) + assert(!"accept() failed"); + + struct sockaddr_un peer_addr; + socklen_t peer_length = sizeof(struct sockaddr_un); + if(getsockname(server_fd, (struct sockaddr *)&peer_addr, &peer_length)) + assert(!"getsockname(server) failed"); + assert(peer_length == (offsetof(sockaddr_un, sun_path) + 14)); + assert(!strcmp(peer_addr.sun_path, NAMED_PATH)); + + memset(&peer_addr, 0, sizeof(struct sockaddr)); + peer_length = sizeof(struct sockaddr_un); + if(getsockname(peer_fd, (struct sockaddr *)&peer_addr, &peer_length)) + assert(!"getsockname(peer) failed"); + assert(peer_length == (offsetof(sockaddr_un, sun_path) + 14)); + assert(!strcmp(peer_addr.sun_path, NAMED_PATH)); + + memset(&peer_addr, 0, sizeof(struct sockaddr)); + peer_length = sizeof(struct sockaddr_un); + if(getpeername(peer_fd, (struct sockaddr *)&peer_addr, &peer_length)) + assert(!"getpeername(peer) failed"); + assert(peer_length == offsetof(sockaddr_un, sun_path)); + + char buf[1]{0}; + if (send(peer_fd, buf, 1, 0) < 0) + assert(!"send() failed"); + } + unlink(NAMED_PATH); +})); + +DEFINE_TEST(epoll_mod_active, ([] { + int e; + int pending; + + int fd = eventfd(0, 0); + assert(fd >= 0); + + int epfd = epoll_create1(0); + assert(epfd >= 0); + + epoll_event evt; + + memset(&evt, 0, sizeof(epoll_event)); + evt.events = 0; + e = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &evt); + assert(!e); + + // Nothing should be pending. + memset(&evt, 0, sizeof(epoll_event)); + pending = epoll_wait(epfd, &evt, 1, 0); + assert(!pending); + + uint64_t n = 1; + auto written = write(fd, &n, sizeof(uint64_t)); + assert(written == sizeof(uint64_t)); + + memset(&evt, 0, sizeof(epoll_event)); + evt.events = EPOLLIN; + e = epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &evt); + assert(!e); + + // The FD should be pending now. + memset(&evt, 0, sizeof(epoll_event)); + pending = epoll_wait(epfd, &evt, 1, 0); + assert(pending == 1); + assert(evt.events & EPOLLIN); + + close(epfd); + close(fd); +})) + +// Use mmap to change the protection flags instead of mprotect. +DEFINE_TEST(mmap_partial_remap, ([] { + //enable_systrace(); + + const int bytes = PAGE_SIZE * 2; + + void *result = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(result != MAP_FAILED); + + void *x = mmap(result, PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); + assert(x != MAP_FAILED); + + void *y = mmap(static_cast(result) + bytes - PAGE_SIZE, PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); + assert(y != MAP_FAILED); +})) + +namespace { + void *offsetBy(void *ptr, ptrdiff_t n) { + return reinterpret_cast( + reinterpret_cast(ptr) + + n); + } + + sigjmp_buf restoreEnv; + + void signalHandler(int, siginfo_t *, void *) { + siglongjmp(restoreEnv, 1); + } + + bool ensureReadable(void *ptr) { + if (sigsetjmp(restoreEnv, 1)) { + return false; + } + + (void)(*reinterpret_cast(ptr)); + + return true; + } + + bool ensureWritable(void *ptr) { + if (sigsetjmp(restoreEnv, 1)) { + return false; + } + + *reinterpret_cast(ptr) = 0; + + return true; + } + + bool ensureNotReadable(void *ptr) { + if (sigsetjmp(restoreEnv, 1)) { + return true; + } + + (void)(*reinterpret_cast(ptr)); + + return false; + } + + bool ensureNotWritable(void *ptr) { + if (sigsetjmp(restoreEnv, 1)) { + return true; + } + + *reinterpret_cast(ptr) = 0; + + return false; + } + + template + void runChecks(Func &&f) { + pid_t pid = fork(); + assert_errno("fork", pid >= 0); + + struct sigaction sa, old_sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = signalHandler; + sa.sa_flags = SA_SIGINFO; + + int ret = sigaction(SIGSEGV, &sa, &old_sa); + assert_errno("sigaction", ret != -1); + + if (pid == 0) { + f(); + exit(0); + } else { + int status = 0; + while (waitpid(pid, &status, 0) == -1) { + if (errno == EINTR) continue; + assert_errno("waitpid", false); + } + + if (WIFSIGNALED(status) || WEXITSTATUS(status) != 0) { + fprintf(stderr, "Test failed on subprocess!\n"); + abort(); + } + + f(); + } + + ret = sigaction(SIGSEGV, &old_sa, nullptr); + assert_errno("sigaction", ret != -1); + } + + const size_t pageSize = sysconf(_SC_PAGESIZE); +} // namespace anonymous + +DEFINE_TEST(mmap_fixed_replace_middle, ([] { + void *mem = mmap(nullptr, pageSize * 3, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + void *newPtr = mmap(offsetBy(mem, pageSize), pageSize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert_errno("mmap", newPtr != MAP_FAILED); + assert(newPtr == offsetBy(mem, pageSize)); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + + assert(ensureReadable(offsetBy(mem, pageSize * 2))); + assert(ensureWritable(offsetBy(mem, pageSize * 2))); + }); + + int ret = munmap(mem, pageSize * 3); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + + assert(ensureNotReadable(offsetBy(mem, pageSize * 2))); + assert(ensureNotWritable(offsetBy(mem, pageSize * 2))); + }); +})) + +DEFINE_TEST(mmap_fixed_replace_left, ([] { + void *mem = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + void *newPtr = mmap(mem, pageSize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert_errno("mmap", newPtr != MAP_FAILED); + assert(newPtr == mem); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureWritable(offsetBy(mem, pageSize))); + }); + + int ret = munmap(mem, pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); +})) + +DEFINE_TEST(mmap_fixed_replace_right, ([] { + void *mem = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + void *newPtr = mmap(offsetBy(mem, pageSize), pageSize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert_errno("mmap", newPtr != MAP_FAILED); + assert(newPtr == offsetBy(mem, pageSize)); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); + + int ret = munmap(mem, pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); +})) + +DEFINE_TEST(mmap_partial_protect_middle, ([] { + void *mem = mmap(nullptr, pageSize * 3, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = mprotect(offsetBy(mem, pageSize), pageSize, PROT_READ); + assert_errno("mprotect", ret != -1); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + + assert(ensureReadable(offsetBy(mem, pageSize * 2))); + assert(ensureWritable(offsetBy(mem, pageSize * 2))); + }); + + ret = munmap(mem, pageSize * 3); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + + assert(ensureNotReadable(offsetBy(mem, pageSize * 2))); + assert(ensureNotWritable(offsetBy(mem, pageSize * 2))); + }); +})) + +DEFINE_TEST(mmap_partial_protect_left, ([] { + void *mem = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = mprotect(mem, pageSize, PROT_READ); + assert_errno("mprotect", ret != -1); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureWritable(offsetBy(mem, pageSize))); + }); + + ret = munmap(mem, pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); +})) + +DEFINE_TEST(mmap_partial_protect_right, ([] { + void *mem = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = mprotect(offsetBy(mem, pageSize), pageSize, PROT_READ); + assert_errno("mprotect", ret != -1); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); + + ret = munmap(mem, pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); +})) + +DEFINE_TEST(mmap_partial_unmap_middle, ([] { + void *mem = mmap(nullptr, pageSize * 3, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = munmap(offsetBy(mem, pageSize), pageSize); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + + assert(ensureReadable(offsetBy(mem, pageSize * 2))); + assert(ensureWritable(offsetBy(mem, pageSize * 2))); + }); + + ret = munmap(mem, pageSize * 3); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + + assert(ensureNotReadable(offsetBy(mem, pageSize * 2))); + assert(ensureNotWritable(offsetBy(mem, pageSize * 2))); + }); +})) + +DEFINE_TEST(mmap_partial_unmap_left, ([] { + void *mem = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = munmap(mem, pageSize); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureReadable(offsetBy(mem, pageSize))); + assert(ensureWritable(offsetBy(mem, pageSize))); + }); + + ret = munmap(mem, pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); +})) + +DEFINE_TEST(mmap_partial_unmap_right, ([] { + void *mem = mmap(nullptr, pageSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = munmap(offsetBy(mem, pageSize), pageSize); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureReadable(mem)); + assert(ensureWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); + + ret = munmap(mem, pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + + assert(ensureNotReadable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize))); + }); +})) + +DEFINE_TEST(mmap_unmap_range_before_first, ([] { + void *mem = mmap(reinterpret_cast(0x100000 + pageSize * 2), pageSize, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + + int ret = munmap(reinterpret_cast(0x100000 + pageSize), pageSize * 2); + assert_errno("munmap", ret != -1); + + runChecks([&] { + assert(ensureNotReadable(mem)); + assert(ensureNotWritable(mem)); + }); +})) + +DEFINE_TEST(mprotect_check_whether_split_mappings_get_protected_correctly, ([] { + void *mem = mmap(NULL, 0x6000, PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + int ret = mprotect(mem, 0x1000, PROT_READ | PROT_WRITE); + assert_errno("mprotect", ret != -1); + ret = mprotect(mem, 0x1000, PROT_READ | PROT_EXEC); + assert_errno("mprotect", ret != -1); + ret = mprotect(mem, 0x5000, PROT_READ | PROT_WRITE); + assert_errno("mprotect", ret != -1); + + runChecks([&] { + assert(ensureWritable(mem)); + }); +})) + +DEFINE_TEST(mprotect_check_whether_three_way_split_mappings_are_handled_correctly, ([] { + void *mem = mmap(NULL, pageSize * 3, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert_errno("mmap", mem != MAP_FAILED); + int ret = mprotect(offsetBy(mem, pageSize), pageSize, PROT_READ | PROT_WRITE); + assert_errno("mprotect", ret != -1); + + runChecks([&] { + assert(ensureNotWritable(mem)); + assert(ensureWritable(offsetBy(mem, pageSize))); + assert(ensureNotWritable(offsetBy(mem, pageSize * 2))); + }); +})) + +DEFINE_TEST(stat, ([] { + // SYM_B -> SYM_A -> /tmp/SYM_REAL + + // TODO: make mknod() + FILE *sym_real = fopen("/tmp/SYM_REAL", "w"); + + if (symlink("/tmp/SYM_REAL", "/tmp/SYM_A") == -1) + assert(!"(1) symlink() failed"); + + if (symlink("/tmp/SYM_A", "/tmp/SYM_B") == -1) + assert(!"(2) symlink() failed"); + + struct stat statbuf; + if (fstatat(AT_FDCWD, "/tmp/SYM_B", &statbuf, AT_SYMLINK_NOFOLLOW) == -1) + assert(!"fstatat() failed"); + + // Check that the symlink is not followed. + assert(S_ISLNK(statbuf.st_mode)); + + if (fstatat(AT_FDCWD, "/tmp/SYM_B", &statbuf, 0) == -1) + assert(!"fstatat() failed"); + + // Check that the symlink is followed. + assert(S_ISREG(statbuf.st_mode)); + + if (unlink("/tmp/SYM_A") == -1) + assert(!"unlink() failed"); + + if (unlink("/tmp/SYM_B") == -1) + assert(!"unlink() failed"); + + fclose(sym_real); + if (unlink("/tmp/SYM_REAL") == -1) + assert(!"unlink() failed"); +})) + +static inline bool cpuid(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + uint32_t cpuid_max; + asm volatile ("cpuid" + : "=a" (cpuid_max) + : "a" (leaf & 0x80000000) : "rbx", "rcx", "rdx"); + if (leaf > cpuid_max) + return false; + asm volatile ("cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "a" (leaf), "c" (subleaf)); + return true; +} + +// Returns [`true`] if the `SYSENTER` and `SYSEXIT` and associated MSRs are supported. +bool has_sysenter_sysexit() { + uint32_t eax, ebx, ecx, edx; + // LEAF 1: Processor and Processor Feature Identifiers + if (!cpuid(1, 0, &eax, &ebx, &ecx, &edx)) { + return false; + } + return edx & (1 << 11); +} + +#if defined(__aero__) +DEFINE_TEST(bad_sysenter, ([] { + if (!has_sysenter_sysexit()) { + printf("test skipped... sysenter not supported\n"); + return; + } + + int pid = fork(); + + if (!pid) { + register long r11 __asm__("r11") = (size_t)0xf0f0 << 48; + register long rcx __asm__("rcx") = (size_t)0xf0f0 << 48; + + asm volatile( + "sysenter\n" + : + : "r"(r11), "r"(rcx) + ); + + __builtin_unreachable(); + } else { + int status = 0; + if (!waitpid(pid, &status, 0)) + assert(!"waitpid() failed"); + + // FIXME: should we get killed with SIGSEGV instead? + assert(WIFEXITED(status)); + } +})) +#endif + +#if defined(__aero__) +DEFINE_TEST(sysenter_system_call, ([] { + if (!has_sysenter_sysexit()) { + printf("test skipped... sysenter not supported\n"); + return; + } + + int fds[2]; + if (pipe(fds) == -1) + assert(!"pipe() failed"); + + int pid = fork(); + + if (!pid) { + close(fds[0]); + + const char *buf = "Hello, world!\n"; + size_t buf_size = strlen(buf); + + __asm__ __volatile__ ( + "mov %%rsp, %%r11\n\t" + "lea 1f(%%rip), %%rcx\n\t" + "sysenter\n\t" + "1:" + : + : "a"(uint64_t(1)), "D"(uint64_t(fds[1])), "S"(buf), "d"(buf_size + 1) + : "rcx", "r11" + ); + + exit(0); + } else { + close(fds[1]); + + int status = 0; + if (!waitpid(pid, &status, 0)) + assert(!"waitpid() failed"); + + assert(WIFEXITED(status)); + + char tmp[15]; + ssize_t n = read(fds[0], tmp, sizeof(tmp)); + + assert(n == 15); + assert(!strcmp(tmp, "Hello, world!\n")); + } +})) +#endif + +std::vector &test_case_ptrs() { + static std::vector singleton; + return singleton; +} + +void abstract_test_case::register_case(abstract_test_case *tcp) { + test_case_ptrs().push_back(tcp); +} + +int main() { + // Go through all tests and run them. + for(abstract_test_case *tcp : test_case_ptrs()) { + std::cout << "tests: Running " << tcp->name() << std::endl; + tcp->run(); + } +} diff --git a/web/CNAME b/web/CNAME deleted file mode 100644 index f6dad86016f..00000000000 --- a/web/CNAME +++ /dev/null @@ -1 +0,0 @@ -aero.andypy.dev \ No newline at end of file diff --git a/web/index.html b/web/index.html deleted file mode 100644 index 6876844fbdf..00000000000 --- a/web/index.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file