diff --git a/.cargo/config.toml b/.cargo/config.toml index 9c7ba798..12e65525 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,4 @@ [build] -target = "riscv64gc-unknown-none-elf" target-dir = 'build' rustflags = ["-C", "force-unwind-tables"] diff --git a/.github/workflows/test-build.yaml b/.github/workflows/test-build.yaml index f6063ab3..f496dae4 100644 --- a/.github/workflows/test-build.yaml +++ b/.github/workflows/test-build.yaml @@ -19,8 +19,10 @@ jobs: include: - arch: riscv64 target: riscv64gc-unknown-none-elf - - arch: loongarch64 - target: loongarch64-unknown-none-softfloat + platform: virt + - arch: x86_64 + target: x86_64-unknown-none + platform: acpi_compat steps: - name: Checkout code uses: actions/checkout@v4 @@ -30,7 +32,8 @@ jobs: - name: Setup QEMU run: | - sudo apt-get install -y qemu-system-${{ matrix.arch }} qemu-kvm + sudo apt-get update + sudo apt-get install -y qemu-system-${{ matrix.arch }} qemu-kvm expect - name: Configure run: ./configure @@ -38,7 +41,7 @@ jobs: - name: Run build for ${{ matrix.arch }} targets run: | make build ARCH=${{ matrix.arch }} MODE=release - zstd -k build/boot-${{ matrix.arch }}.img + zstd -k build/boot-${{ matrix.arch }}-${{ matrix.platform }}.img - name: Upload build artifacts uses: actions/upload-artifact@v4 @@ -46,7 +49,7 @@ jobs: name: eonix-kernel-and-image-${{ matrix.arch }} path: | build/${{ matrix.target }}/release/eonix_kernel - build/boot-${{ matrix.arch }}.img.zst + build/boot-${{ matrix.arch }}-${{ matrix.platform }}.img.zst - name: Test run for ${{ matrix.arch }} run: | diff --git a/.gitignore b/.gitignore index fbc2a9b1..4684b698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ build/ .idea/ +.vscode/settings.json test/ diff --git a/.vscode/settings.example.json b/.vscode/settings.example.json new file mode 100644 index 00000000..fbafa867 --- /dev/null +++ b/.vscode/settings.example.json @@ -0,0 +1,10 @@ +{ + "editor.formatOnSave": true, + // Uncomment and set the target you'd like to use for analysis. + // + // Available targets: + // - x86_64-unknown-none.json + // - riscv64gc-unknown-none-elf + // - loongarch64-unknown-none-softfloat + // "rust-analyzer.cargo.target": "x86_64-unknown-none.json", +} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 634d16af..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "makefile.configureOnOpen": false, -} diff --git a/Makefile.src b/Makefile.src index ab13f5b8..eca1eda4 100644 --- a/Makefile.src +++ b/Makefile.src @@ -54,6 +54,8 @@ endif ifeq ($(ARCH),riscv64) +PLATFORM ?= virt + BINARY_DIR_BASE := build/riscv64gc-unknown-none-elf BINARY_DIR := $(BINARY_DIR_BASE)/$(MODE) @@ -61,7 +63,7 @@ QEMU_ARGS += \ -machine virt -kernel $(BINARY_DIR)/eonix_kernel \ -device virtio-blk-device,drive=disk0,bus=virtio-mmio-bus.0 \ -device virtio-net-device,netdev=mynet0 \ - -drive id=disk0,file=build/boot-riscv64.img,format=raw,if=none \ + -drive id=disk0,file=build/boot-riscv64-virt.img,format=raw,if=none \ -netdev user,id=mynet0 \ -rtc base=utc @@ -73,11 +75,10 @@ endif CARGO_FLAGS += --target riscv64gc-unknown-none-elf -.PHONY: build -build: $(BINARY_DIR)/eonix_kernel build/boot-riscv64.img - else ifeq ($(ARCH),loongarch64) +PLATFORM ?= virt + BINARY_DIR_BASE := build/loongarch64-unknown-none-softfloat BINARY_DIR := $(BINARY_DIR_BASE)/$(MODE) @@ -85,7 +86,7 @@ QEMU_ARGS += \ -machine virt -kernel $(BINARY_DIR)/eonix_kernel -m 1G \ -device virtio-blk-pci,drive=disk0 \ -device virtio-net-pci,netdev=mynet0 \ - -drive id=disk0,file=build/boot-loongarch64.img,format=raw,if=none \ + -drive id=disk0,file=build/boot-loongarch64-virt.img,format=raw,if=none \ -netdev user,id=mynet0,hostfwd=tcp::5555-:5555,hostfwd=udp::5555-:5555 \ -rtc base=utc @@ -97,11 +98,10 @@ endif CARGO_FLAGS += --target loongarch64-unknown-none-softfloat -.PHONY: build -build: $(BINARY_DIR)/eonix_kernel build/boot-loongarch64.img - else ifeq ($(ARCH),x86_64) +PLATFORM ?= acpi_compat + BINARY_DIR_BASE := build/x86_64-unknown-none BINARY_DIR := $(BINARY_DIR_BASE)/$(MODE) @@ -110,7 +110,7 @@ QEMU_ARGS += \ -device ahci,id=ahci \ -device ide-hd,drive=disk0,bus=ahci.0 \ -device e1000e,netdev=mynet0 \ - -drive id=disk0,file=build/boot-x86_64.img,format=raw,if=none \ + -drive id=disk0,file=build/boot-x86_64-acpi_compat.img,format=raw,if=none \ -netdev user,id=mynet0 ifneq ($(IMG),) @@ -121,11 +121,13 @@ endif CARGO_FLAGS += --target x86_64-unknown-none.json -.PHONY: build -build: $(BINARY_DIR)/eonix_kernel build/boot-x86_64.img - endif +TARGET := $(ARCH)-$(PLATFORM) + +.PHONY: build +build: $(BINARY_DIR)/eonix_kernel build/boot-$(TARGET).img + .PHONY: run run: build build/kernel.sym $(QEMU) $(QEMU_ARGS) -display none -serial mon:stdio @@ -173,8 +175,8 @@ $(BINARY_DIR)/eonix_kernel: $(KERNEL_DEPS) build/kernel.sym: $(BINARY_DIR)/eonix_kernel CARGO_TARGET_DIR=build cargo objcopy -q $(CARGO_FLAGS) -- --only-keep-debug build/kernel.sym -build/fs-%.img: user-programs/init_script_%.sh script/build-img.sh $(USER_PROGRAMS) - ARCH=$* OUTPUT=$@ sh script/build-img.sh +build/fs-%.img: user-programs/init_script_%.sh script/build-img/build-img $(USER_PROGRAMS) + script/build-img/build-img -t $* -o $@ build/mbr.bin: $(BINARY_DIR)/eonix_kernel CARGO_TARGET_DIR=build cargo objcopy -q $(CARGO_FLAGS) -- -O binary -j .mbr build/mbr.bin @@ -186,7 +188,7 @@ build/kernel.bin: $(BINARY_DIR)/eonix_kernel CARGO_TARGET_DIR=build cargo objcopy -q $(CARGO_FLAGS) -- -O binary --strip-debug \ -R .mbr -R .stage1 build/kernel.bin -build/boot-x86_64.img: build/fs-x86_64.img build/mbr.bin build/stage1.bin build/kernel.bin +build/boot-x86_64-acpi_compat.img: build/fs-x86_64-acpi_compat.img build/mbr.bin build/stage1.bin build/kernel.bin dd if=build/mbr.bin of=$@ bs=512 count=1 conv=notrunc 2> /dev/null dd if=build/stage1.bin of=$@ bs=512 seek=1 conv=notrunc 2> /dev/null dd if=build/kernel.bin of=$@ bs=4096 seek=1 conv=notrunc 2> /dev/null @@ -195,13 +197,13 @@ build/boot-x86_64.img: build/fs-x86_64.img build/mbr.bin build/stage1.bin build/ sh -c 'echo n; echo; echo; echo 8192; echo; echo a; echo w' \ | $(FDISK) $@ 2> /dev/null > /dev/null -build/boot-riscv64.img: build/fs-riscv64.img +build/boot-riscv64-virt.img: build/fs-riscv64-virt.img dd if=$< of=$@ bs=$(shell expr 4 \* 1024 \* 1024) \ seek=1 conv=notrunc 2> /dev/null sh -c 'echo n; echo; echo; echo 8192; echo; echo a; echo w' \ | $(FDISK) $@ 2> /dev/null > /dev/null -build/boot-loongarch64.img: build/fs-loongarch64.img +build/boot-loongarch64-virt.img: build/fs-loongarch64-virt.img dd if=$< of=$@ bs=$(shell expr 4 \* 1024 \* 1024) \ seek=1 conv=notrunc 2> /dev/null sh -c 'echo n; echo; echo; echo 8192; echo; echo a; echo w' \ diff --git a/rust-toolchain b/rust-toolchain index 8adb8e58..11ad5efd 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2025-05-16 +nightly-2026-01-09 diff --git a/script/build-img.sh b/script/build-img.sh deleted file mode 100644 index 6a83638f..00000000 --- a/script/build-img.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh - -OS=`uname -s` - -if sudo --version > /dev/null 2>&1; then - SUDO=sudo -fi - -if [ "$OUTPUT" = "" ]; then - OUTPUT="build/fs-$ARCH.img" -fi - -if [ "$ARCH" = "" ]; then - echo "ARCH is not set, exiting..." >&2 - exit 1 -fi - -dd if=/dev/zero of="$OUTPUT" bs=`expr 1024 \* 1024` count=1020 -mkfs.fat -n SYSTEM "$OUTPUT" - -if [ "$OS" = "Darwin" ]; then - SUDO='' - hdiutil detach build/mnt > /dev/null 2>&1 || true - hdiutil attach "$OUTPUT" -mountpoint build/mnt -else - mkdir -p build/mnt - $SUDO losetup -P /dev/loop2 "$OUTPUT" - $SUDO mount /dev/loop2 build/mnt -fi - -if [ "$ARCH" = "x86_64" ]; then - $SUDO cp ./user-programs/init.out build/mnt/init - $SUDO cp ./user-programs/int.out build/mnt/int - $SUDO cp ./user-programs/dynamic_test build/mnt/dynamic_test - $SUDO cp ./user-programs/busybox build/mnt/busybox - $SUDO cp ./user-programs/busybox-minimal build/mnt/busybox_ - $SUDO cp ./user-programs/ld-musl-i386.so.1 build/mnt/ld-musl-i386.so.1 - $SUDO cp ./user-programs/pthread_test build/mnt/pthread_test - $SUDO cp ./user-programs/init_script_x86_64.sh build/mnt/initsh -elif [ "$ARCH" = "riscv64" ]; then - $SUDO cp ./user-programs/busybox.static build/mnt/busybox - $SUDO cp ./user-programs/init_script_riscv64.sh build/mnt/initsh -elif [ "$ARCH" = "loongarch64" ]; then - $SUDO cp ./user-programs/busybox.la64 build/mnt/busybox - $SUDO cp ./user-programs/init_script_loongarch64.sh build/mnt/initsh -fi - -# Add your custom files here - - -# End of custom files - -if [ "$OS" = "Darwin" ]; then - hdiutil detach build/mnt -else - $SUDO losetup -d /dev/loop2 - $SUDO umount build/mnt -fi diff --git a/script/build-img/build-img b/script/build-img/build-img new file mode 100755 index 00000000..638866af --- /dev/null +++ b/script/build-img/build-img @@ -0,0 +1,94 @@ +#!/bin/sh +# shellcheck source=./lib/lib.sh + +. "$(dirname "$(realpath "$0")")/lib/lib.sh" + +BASE_DIR="$(dirname "$(realpath "$0")")" + +KB=1024 +MB=$((1024 * KB)) + +TARGET= +IMAGE= +MOUNTPOINT="$(mktemp -d)" + +usage() { + cat >&2 < -o [-h] + +Options + -t The target building image for + [available: riscv64 x86 loongarch64] + -o Output image path + -h Show help message +EOF + + exit "$1" +} + +ensure_mount_macos() { + hdiutil detach "$MOUNTPOINT" > /dev/null 2>&1 || : + hdiutil attach "$IMAGE" -mountpoint "$MOUNTPOINT" +} + +ensure_mount_linux() { + DEV=$(sudo losetup -f "$IMAGE" --show) + sudo mount "$DEV" "$MOUNTPOINT" +} + +ensure_mount() { + if [ "$OS" = Darwin ]; then + ensure_mount_macos + return + fi + + ensure_mount_linux +} + +unmount_macos() { + hdiutil detach "$MOUNTPOINT" +} + +unmount_linux() { + sudo umount "$MOUNTPOINT" + sudo losetup -d "$DEV" +} + +cleanup() { + case "$OS" in + Darwin) + unmount_macos + ;; + *) + unmount_linux + ;; + esac +} + +set -eu + +while getopts "t:o:h" opt; do + case "$opt" in + t) TARGET="$OPTARG";; + o) IMAGE="$OPTARG";; + h) usage 0;; + ?) usage 1;; + esac +done + +shift $((OPTIND - 1)) + +[ -z "$TARGET" ] && die "ARCH is not set" +[ -z "$IMAGE" ] && die "output image path is not set" + +echo "Build image with ARCH=$TARGET OUTPUT=$IMAGE MOUNTPOINT=$MOUNTPOINT" + +dd if=/dev/zero of="$IMAGE" bs=$((1 * MB)) count=$((1024 - 4)) +mkfs.fat -n SYSTEM "$IMAGE" + +ensure_mount +trap cleanup EXIT + +for name in $(iter_files_sorted "$BASE_DIR/platform/$TARGET"); do + ( . "$name" ) +done diff --git a/script/build-img/lib/lib.sh b/script/build-img/lib/lib.sh new file mode 100644 index 00000000..5cc6c036 --- /dev/null +++ b/script/build-img/lib/lib.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +OS=$(uname -s) +SUDO=$(which sudo || :) + +info() { + echo "info : $1" +} + +warn() { + echo "warn : $1" >&2 +} + +error() { + echo "fatal: $1" >&2 +} + +die() { + error "$1" && exit 1 +} + +sudo() { + "$SUDO" "$@" +} + +copy_to_image() { + _prefix=sudo + [ "$OS" = Darwin ] && _prefix= + + $_prefix cp "$1" "$MOUNTPOINT/$2" +} + +iter_files() { + find -L "$1" -maxdepth 1 -type f +} + +iter_files_sorted() { + iter_files "$@" | sort +} diff --git a/script/build-img/platform/loongarch64-virt/10-base.sh b/script/build-img/platform/loongarch64-virt/10-base.sh new file mode 100644 index 00000000..d0f21dbd --- /dev/null +++ b/script/build-img/platform/loongarch64-virt/10-base.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# shellcheck source=./../../lib/lib.sh + +copy_to_image user-programs/busybox.la64 busybox +copy_to_image user-programs/init_script_loongarch64-virt.sh initsh diff --git a/script/build-img/platform/riscv64-virt/10-base.sh b/script/build-img/platform/riscv64-virt/10-base.sh new file mode 100644 index 00000000..efb32cf7 --- /dev/null +++ b/script/build-img/platform/riscv64-virt/10-base.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# shellcheck source=./../../lib/lib.sh + +copy_to_image user-programs/busybox.static busybox +copy_to_image user-programs/init_script_riscv64-virt.sh initsh diff --git a/script/build-img/platform/riscv64-virt/20-tests.sh b/script/build-img/platform/riscv64-virt/20-tests.sh new file mode 100644 index 00000000..1d9e0d71 --- /dev/null +++ b/script/build-img/platform/riscv64-virt/20-tests.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +name="$(mktemp)" + +cat > "$name" <&2 +die() { + echo "error: $1" >&2 exit 1 -fi +} + +runcmd() { + _cmd=$(printf "%q" "$*") + + cat < /dev/null && echo TEST\ $$\ WITH\ ARCH=$ARCH\ PASSED +$(runcmd ls -la) + +$(wait_str proc) + +$(runcmd echo \""$SUCCESS_MSG"\") + +$(wait_str "\n$SUCCESS_MSG") + +$(runcmd poweroff) + +$(wait_init_exit) + +EOF + +status=$? + +echo + +# shellcheck disable=SC2181 +if [ $status -ne 0 ]; then + echo "=== Test $$ with ARCH=$ARCH failed" +else + echo "=== Test $$ with ARCH=$ARCH passed" +fi diff --git a/user-programs/init_script_loongarch64.sh b/user-programs/init_script_loongarch64-virt.sh similarity index 100% rename from user-programs/init_script_loongarch64.sh rename to user-programs/init_script_loongarch64-virt.sh diff --git a/user-programs/init_script_riscv64-virt.sh b/user-programs/init_script_riscv64-virt.sh new file mode 100644 index 00000000..b5ce95d7 --- /dev/null +++ b/user-programs/init_script_riscv64-virt.sh @@ -0,0 +1,113 @@ +#!/mnt/busybox sh + +BUSYBOX=/mnt/busybox +TERMINAL=/dev/ttyS0 +VERBOSE= + +error() { + printf "\033[91merror: \033[0m%s\n" "$1" >&2 +} + +warn() { + printf "\033[93mwarn : \033[0m%s\n" "$1" >&2 +} + +info() { + printf "\033[92minfo : \033[0m%s\n" "$1" >&2 +} + +die() { + error "$1" && freeze +} + +freeze() { + info "freezing..." >&2 + while true; do + : + done + + exit 1 +} + +unrecoverable() { + die "unrecoverable error occurred. check the message above." +} + +busybox() { + $BUSYBOX "$@" +} + +trap unrecoverable EXIT + +set -euo pipefail + +if [ -n "$VERBOSE" ]; then + set -x +fi + +busybox mkdir -p /dev + +busybox mknod -m 666 /dev/console c 5 1 +busybox mknod -m 666 /dev/null c 1 3 +busybox mknod -m 666 /dev/zero c 1 5 +busybox mknod -m 666 /dev/vda b 8 0 +busybox mknod -m 666 /dev/vda1 b 8 1 +busybox mknod -m 666 /dev/vdb b 8 16 +busybox mknod -m 666 /dev/ttyS0 c 4 64 +busybox mknod -m 666 /dev/ttyS1 c 4 65 + +info "deploying busybox..." + +busybox mkdir -p /bin /lib +busybox --install -s /bin + +info "done" + +export PATH="/bin" + +mkdir -p /etc /root /proc +mount -t procfs proc proc + +cat > /etc/passwd < /etc/group < /etc/profile < /root/.profile < /root/test.c < + +int main() { + int var = 0; + printf("Hello, world!\n"); + printf("Please input a number: \n"); + scanf("%d", &var); + if (var > 0) { + printf("You typed a positive number.\n"); + } else if (var == 0 ) { + printf("You input a zero.\n"); + } else { + printf("You typed a negative number.\n"); + } + return 0; +} +EOF + +# shellcheck disable=SC2094 +exec sh -l < "$TERMINAL" > "$TERMINAL" 2> "$TERMINAL" + +# We don't have a working init yet, so we use busybox sh directly for now. +# exec /mnt/init /bin/sh -c 'exec sh -l < /dev/ttyS0 > /dev/ttyS0 2> /dev/ttyS0' diff --git a/user-programs/init_script_riscv64.sh b/user-programs/init_script_riscv64.sh deleted file mode 100644 index 52b2628c..00000000 --- a/user-programs/init_script_riscv64.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/mnt/busybox sh - -BUSYBOX=/mnt/busybox - -freeze() { - echo "an error occurred while executing '''$@''', freezing..." >&2 - - while true; do - true - done -} - -do_or_freeze() { - if $@; then - return - fi - - freeze $@ -} - -do_or_freeze $BUSYBOX mkdir -p /dev - -do_or_freeze $BUSYBOX mknod -m 666 /dev/console c 5 1 -do_or_freeze $BUSYBOX mknod -m 666 /dev/null c 1 3 -do_or_freeze $BUSYBOX mknod -m 666 /dev/zero c 1 5 -do_or_freeze $BUSYBOX mknod -m 666 /dev/vda b 8 0 -do_or_freeze $BUSYBOX mknod -m 666 /dev/vda1 b 8 1 -do_or_freeze $BUSYBOX mknod -m 666 /dev/vdb b 8 16 -do_or_freeze $BUSYBOX mknod -m 666 /dev/ttyS0 c 4 64 -do_or_freeze $BUSYBOX mknod -m 666 /dev/ttyS1 c 4 65 - -echo -n -e "deploying busybox... " >&2 - -do_or_freeze $BUSYBOX mkdir -p /bin -do_or_freeze $BUSYBOX --install -s /bin -do_or_freeze $BUSYBOX mkdir -p /lib - -export PATH="/bin" - -echo ok >&2 - -do_or_freeze mkdir -p /etc /root /proc -do_or_freeze mount -t procfs proc proc - -# Check if the device /dev/vdb is available and can be read -if dd if=/dev/vdb of=/dev/null bs=512 count=1; then - echo -n -e "Mounting the ext4 image... " >&2 - do_or_freeze mkdir -p /mnt1 - do_or_freeze mount -t ext4 /dev/vdb /mnt1 - echo ok >&2 -fi - -cp /mnt/ld-musl-i386.so.1 /lib/ld-musl-i386.so.1 -ln -s /lib/ld-musl-i386.so.1 /lib/libc.so - -cat > /etc/passwd < /etc/group < /etc/profile < /root/.profile < /root/test.c < - -int main() { - int var = 0; - printf("Hello, world!\n"); - printf("Please input a number: \n"); - scanf("%d", &var); - if (var > 0) { - printf("You typed a positive number.\n"); - } else if (var == 0 ) { - printf("You input a zero.\n"); - } else { - printf("You typed a negative number.\n"); - } - return 0; -} -EOF - -exec $BUSYBOX sh -l < /dev/ttyS0 > /dev/ttyS0 2> /dev/ttyS0 - -# We don't have a working init yet, so we use busybox sh directly for now. -# exec /mnt/init /bin/sh -c 'exec sh -l < /dev/ttyS0 > /dev/ttyS0 2> /dev/ttyS0' diff --git a/user-programs/init_script_x86_64.sh b/user-programs/init_script_x86_64-acpi_compat.sh similarity index 100% rename from user-programs/init_script_x86_64.sh rename to user-programs/init_script_x86_64-acpi_compat.sh diff --git a/x86_64-unknown-none.json b/x86_64-unknown-none.json index 77e4d1dd..a66b07ba 100644 --- a/x86_64-unknown-none.json +++ b/x86_64-unknown-none.json @@ -3,8 +3,8 @@ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", + "target-pointer-width": 64, + "target-c-int-width": 32, "os": "none", "executables": true, "linker-flavor": "ld.lld",