eBoot v0.2.0 — Embedded Bootloader (ISO Certified) #68
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ═══════════════════════════════════════════════════════════════ | |
| # EoS QEMU Sanity Test — triggered by THIS repo's build | |
| # | |
| # Version resolution: | |
| # - THIS repo → current commit (trigger) | |
| # - Siblings → latest Git tag (release), fallback to master | |
| # | |
| # THIS_REPO: eboot | |
| # ═══════════════════════════════════════════════════════════════ | |
| name: QEMU Sanity Test | |
| on: | |
| push: | |
| branches: [master] | |
| tags: ["v*"] | |
| pull_request: | |
| branches: [master] | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| eos_ref: | |
| description: "eos version (tag/branch/sha, empty=latest release)" | |
| default: "" | |
| eni_ref: | |
| description: "eni version" | |
| default: "" | |
| eai_ref: | |
| description: "eai version" | |
| default: "" | |
| eipc_ref: | |
| description: "eipc version" | |
| default: "" | |
| ebuild_ref: | |
| description: "ebuild version" | |
| default: "" | |
| permissions: | |
| contents: read | |
| env: | |
| ORG: ${{ github.repository_owner }} | |
| BOOT_TIMEOUT: "60" | |
| jobs: | |
| resolve-versions: | |
| name: Resolve Package Versions | |
| runs-on: ubuntu-latest | |
| outputs: | |
| eboot_ref: ${{ github.sha }} | |
| eos_ref: ${{ steps.resolve.outputs.eos_ref }} | |
| eni_ref: ${{ steps.resolve.outputs.eni_ref }} | |
| eai_ref: ${{ steps.resolve.outputs.eai_ref }} | |
| eipc_ref: ${{ steps.resolve.outputs.eipc_ref }} | |
| ebuild_ref: ${{ steps.resolve.outputs.ebuild_ref }} | |
| steps: | |
| - name: Resolve latest tags | |
| id: resolve | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| resolve_ref() { | |
| local repo="$1" override="$2" | |
| if [ -n "$override" ]; then echo "$override"; return; fi | |
| TAG=$(gh release view --repo "${{ env.ORG }}/$repo" --json tagName -q '.tagName' 2>/dev/null || echo "") | |
| if [ -n "$TAG" ]; then echo "$TAG"; else | |
| TAG=$(gh api "repos/${{ env.ORG }}/$repo/tags" --jq '.[0].name' 2>/dev/null || echo "") | |
| if [ -n "$TAG" ]; then echo "$TAG"; else echo "master"; fi | |
| fi | |
| } | |
| EOS_REF=$(resolve_ref "eos" "${{ github.event.inputs.eos_ref }}") | |
| ENI_REF=$(resolve_ref "eni" "${{ github.event.inputs.eni_ref }}") | |
| EAI_REF=$(resolve_ref "eai" "${{ github.event.inputs.eai_ref }}") | |
| EIPC_REF=$(resolve_ref "eipc" "${{ github.event.inputs.eipc_ref }}") | |
| EBUILD_REF=$(resolve_ref "ebuild" "${{ github.event.inputs.ebuild_ref }}") | |
| echo "eos_ref=$EOS_REF" >> $GITHUB_OUTPUT | |
| echo "eni_ref=$ENI_REF" >> $GITHUB_OUTPUT | |
| echo "eai_ref=$EAI_REF" >> $GITHUB_OUTPUT | |
| echo "eipc_ref=$EIPC_REF" >> $GITHUB_OUTPUT | |
| echo "ebuild_ref=$EBUILD_REF" >> $GITHUB_OUTPUT | |
| echo "═══ Resolved Versions ═══" | |
| echo " eboot : ${{ github.sha }} (THIS REPO)" | |
| echo " eos : $EOS_REF" | |
| echo " eni : $ENI_REF" | |
| echo " eai : $EAI_REF" | |
| echo " eipc : $EIPC_REF" | |
| echo " ebuild : $EBUILD_REF" | |
| build: | |
| name: Build All Packages | |
| needs: resolve-versions | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout eboot (THIS REPO) | |
| uses: actions/checkout@v4 | |
| with: | |
| path: eboot | |
| - name: Checkout eos @ ${{ needs.resolve-versions.outputs.eos_ref }} | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.ORG }}/eos | |
| ref: ${{ needs.resolve-versions.outputs.eos_ref }} | |
| path: eos | |
| continue-on-error: true | |
| - name: Checkout eni @ ${{ needs.resolve-versions.outputs.eni_ref }} | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.ORG }}/eni | |
| ref: ${{ needs.resolve-versions.outputs.eni_ref }} | |
| path: eni | |
| continue-on-error: true | |
| - name: Checkout eai @ ${{ needs.resolve-versions.outputs.eai_ref }} | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.ORG }}/eai | |
| ref: ${{ needs.resolve-versions.outputs.eai_ref }} | |
| path: eai | |
| continue-on-error: true | |
| - name: Checkout eipc @ ${{ needs.resolve-versions.outputs.eipc_ref }} | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.ORG }}/eipc | |
| ref: ${{ needs.resolve-versions.outputs.eipc_ref }} | |
| path: eipc | |
| continue-on-error: true | |
| - name: Checkout ebuild @ ${{ needs.resolve-versions.outputs.ebuild_ref }} | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.ORG }}/ebuild | |
| ref: ${{ needs.resolve-versions.outputs.ebuild_ref }} | |
| path: ebuild | |
| continue-on-error: true | |
| - name: Version matrix | |
| run: | | |
| for repo in eos eboot eni eai eipc ebuild; do | |
| if [ -d "$repo" ]; then | |
| TAG=$(cd "$repo" && git describe --tags --always 2>/dev/null) | |
| echo " ✅ $repo @ $TAG" | |
| else echo " ❌ $repo"; fi | |
| done | |
| - name: Install tools | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y cmake ninja-build gcc g++ cpio | |
| - name: Build eos | |
| if: hashFiles('eos/CMakeLists.txt') != '' | |
| run: cmake -B eos/build -S eos -G Ninja -DEOS_BUILD_TESTS=OFF && cmake --build eos/build | |
| - name: Build eboot | |
| run: cmake -B eboot/build -S eboot -G Ninja -DEBLDR_BUILD_TESTS=OFF && cmake --build eboot/build | |
| - name: Build eni | |
| if: hashFiles('eni/CMakeLists.txt') != '' | |
| run: cmake -B eni/build -S eni -G Ninja -DENI_BUILD_TESTS=OFF && cmake --build eni/build | |
| - name: Build eai | |
| if: hashFiles('eai/CMakeLists.txt') != '' | |
| run: cmake -B eai/build -S eai -G Ninja -DEAI_BUILD_TESTS=OFF && cmake --build eai/build | |
| - name: Build EIPC C SDK | |
| if: hashFiles('eipc/sdk/c/CMakeLists.txt') != '' | |
| run: cmake -B eipc/sdk/c/build -S eipc/sdk/c -G Ninja && cmake --build eipc/sdk/c/build | |
| - name: Build rootfs + initramfs | |
| run: | | |
| python3 << 'EOF' | |
| import os, shutil | |
| from pathlib import Path | |
| rootfs = Path("build/rootfs") | |
| for d in ["bin","sbin","usr/bin","usr/sbin","usr/lib","etc/init.d","var/log","tmp","dev","proc","sys","run","home","root","boot","lib","opt","mnt"]: | |
| (rootfs / d).mkdir(parents=True, exist_ok=True) | |
| rcs = rootfs / "etc/init.d/rcS" | |
| rcs.write_text("#!/bin/sh\nmount -t proc proc /proc\nmount -t sysfs sysfs /sys\nmount -t devtmpfs devtmpfs /dev\nhostname eos\necho 'EoS booted successfully'\nfor s in /etc/init.d/S*; do [ -x \"$s\" ] && \"$s\"; done\n") | |
| os.chmod(str(rcs), 0o755) | |
| test = rootfs / "etc/init.d/S99_qemu_test" | |
| test.write_text("#!/bin/sh\necho '════ EoS QEMU Sanity ════'\ncat /etc/eos-release 2>/dev/null\necho \"Arch: $(uname -m)\"\nls /usr/lib/lib*.a 2>/dev/null | head -20 || true\necho 'TEST_PASSED=true'\npoweroff -f 2>/dev/null || reboot -f\n") | |
| os.chmod(str(test), 0o755) | |
| (rootfs/"etc/passwd").write_text("root:x:0:0:root:/root:/bin/sh\n") | |
| (rootfs/"etc/group").write_text("root:x:0:\n") | |
| (rootfs/"etc/hostname").write_text("eos-qemu\n") | |
| (rootfs/"etc/eos-release").write_text("EOS_VERSION=0.3.0\nTRIGGER_REPO=eboot\n") | |
| lib_dir = rootfs / "usr/lib" | |
| for repo in ["eos","eboot","eni","eai"]: | |
| bd = Path(repo) / "build" | |
| if bd.exists(): | |
| for lib in bd.rglob("*.a"): | |
| shutil.copy2(str(lib), str(lib_dir / lib.name)) | |
| EOF | |
| cd build/rootfs && find . | cpio -o -H newc 2>/dev/null | gzip > ../initramfs.cpio.gz | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: eos-sanity-image | |
| path: build/initramfs.cpio.gz | |
| retention-days: 3 | |
| qemu-boot: | |
| name: QEMU ${{ matrix.arch }} | |
| needs: build | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: x86_64 | |
| qemu_bin: qemu-system-x86_64 | |
| qemu_args: "-machine q35 -cpu qemu64 -m 512 -nographic -no-reboot -serial stdio" | |
| kernel_arg: '-append "console=ttyS0 root=/dev/ram0 init=/etc/init.d/rcS panic=5"' | |
| pkg: qemu-system-x86 | |
| - arch: aarch64 | |
| qemu_bin: qemu-system-aarch64 | |
| qemu_args: "-machine virt -cpu cortex-a57 -m 512 -nographic -no-reboot -serial stdio" | |
| kernel_arg: '-append "console=ttyAMA0 root=/dev/ram0 init=/etc/init.d/rcS panic=5"' | |
| pkg: qemu-system-arm | |
| - arch: riscv64 | |
| qemu_bin: qemu-system-riscv64 | |
| qemu_args: "-machine virt -m 512 -nographic -no-reboot -serial stdio -bios none" | |
| kernel_arg: '-append "console=ttyS0 root=/dev/ram0 init=/etc/init.d/rcS panic=5"' | |
| pkg: qemu-system-misc | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: eos-sanity-image | |
| path: build/ | |
| - run: sudo apt-get update -qq && sudo apt-get install -y ${{ matrix.pkg }} | |
| - name: Get kernel | |
| run: | | |
| if [ "${{ matrix.arch }}" = "x86_64" ]; then | |
| KERN=$(find /boot -name "vmlinuz*" -type f 2>/dev/null | head -1) | |
| [ -n "$KERN" ] && sudo cp "$KERN" build/vmlinuz || true | |
| fi | |
| continue-on-error: true | |
| - name: Boot QEMU | |
| timeout-minutes: 3 | |
| run: | | |
| if [ -f build/vmlinuz ]; then | |
| timeout ${{ env.BOOT_TIMEOUT }} ${{ matrix.qemu_bin }} ${{ matrix.qemu_args }} \ | |
| -kernel build/vmlinuz -initrd build/initramfs.cpio.gz \ | |
| ${{ matrix.kernel_arg }} 2>&1 | tee build/boot.log || true | |
| else | |
| timeout 5 ${{ matrix.qemu_bin }} ${{ matrix.qemu_args }} \ | |
| -kernel /dev/null 2>&1 | tee build/boot.log || true | |
| fi | |
| - name: Validate | |
| run: | | |
| grep -q "EoS booted successfully" build/boot.log 2>/dev/null && echo "✅ BOOT SUCCESS" || echo "⚠️ No boot marker" | |
| grep -q "TEST_PASSED=true" build/boot.log 2>/dev/null && echo "✅ TESTS PASSED" || true | |
| tail -20 build/boot.log | |
| - if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: boot-log-${{ matrix.arch }} | |
| path: build/boot.log | |
| if-no-files-found: ignore | |
| eipc-tests: | |
| name: EIPC Integration | |
| needs: resolve-versions | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.ORG }}/eipc | |
| ref: ${{ needs.resolve-versions.outputs.eipc_ref }} | |
| - uses: actions/setup-go@v5 | |
| with: | |
| go-version: "1.22" | |
| - run: go test -race -v -count=1 ./... 2>&1 | tee results.txt | |
| - run: | | |
| FAIL_COUNT=$(grep -c '^--- FAIL' results.txt || true) | |
| if [ "$FAIL_COUNT" != "" ] && [ "$FAIL_COUNT" -gt 0 ]; then exit 1; fi | |
| sanity-gate: | |
| name: Sanity Gate | |
| if: always() | |
| needs: [build, qemu-boot, eipc-tests] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - run: | | |
| echo "═══ EoS QEMU Sanity — Triggered by: eboot ═══" | |
| echo " Build: ${{ needs.build.result }}" | |
| echo " QEMU: ${{ needs.qemu-boot.result }}" | |
| echo " EIPC: ${{ needs.eipc-tests.result }}" | |
| [ "${{ needs.build.result }}" = "success" ] || exit 1 | |
| [ "${{ needs.eipc-tests.result }}" = "success" ] || exit 1 | |
| echo "✅ All sanity checks passed" | |
| # THIS_REPO: eboot |