diff --git a/.cargo/config.toml b/.cargo/config.toml index 7ad47c0..c9d99de 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,4 +2,4 @@ target = "aarch64-unknown-none-softfloat" [target.aarch64-unknown-none-softfloat] -runner = "./qemu-runner.sh" +runner = "scripts/qemu-runner.sh" diff --git a/.gitignore b/.gitignore index 0f41a4a..438bcb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target +/build .gdb_history *.img diff --git a/README.md b/README.md index 1aea7a3..ff0ff7d 100644 --- a/README.md +++ b/README.md @@ -66,12 +66,10 @@ x86) before running on bare metal. ## Building and Running ### Prerequisites -You will need QEMU for aarch64 emulation, dosfstools to create the virtual file system -and gcc-aarch64-linux-gnu to compile bash for the image. +You will need QEMU for aarch64 emulation and dosfstools to create the virtual file system. ```bash -# Install QEMU (Ubuntu/Debian), dosfstools and gcc-aarch64-linux-gnu -sudo apt install qemu-system-aarch64 dosfstools gcc-aarch64-linux-gnu +sudo apt install qemu-system-aarch64 dosfstools ``` Additionally you will need a version of the [aarch64-none-elf](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) toolchain installed. @@ -87,6 +85,27 @@ Run the following command nix shell nixpkgs#pkgsCross.aarch64-embedded.stdenv.cc nixpkgs#pkgsCross.aarch64-embedded.stdenv.cc.bintools ``` +### Preparing the image + +First, run the following script to prepare the binaries for the image: +```bash +./scripts/build-deps.sh +``` + +This will download and build the necessary dependencies for the kernel and put them +into the `build` directory. + +Once that is done, you can create the image using the following command: +```bash +sudo ./scripts/create-image.sh +``` + +This will create an image file named `moss.img` in the root directory of the project, +format it as VFAT 32 and create the necessary files and directories for the kernel. + +This script needs to run with sudo to mount the image through a loop device, +which is required to properly create the image for the kernel to work. + ### Running via QEMU To build the kernel and launch it in QEMU: diff --git a/mkrootfs-aarch64.sh b/mkrootfs-aarch64.sh deleted file mode 100755 index e8f2f5a..0000000 --- a/mkrootfs-aarch64.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -IMG="test.img" -MOUNT="/mnt/moss" - -if [ -f "$IMG" ]; then - echo "initrd file $IMG already exists. Skipping." - exit 0 -fi - -dd if=/dev/zero of="$IMG" bs=1M count=128 -mkfs.vfat -F 32 "$IMG" - -if ! mountpoint -q "$MOUNT"; then - mount -o loop "$IMG" "$MOUNT" -fi - -if [ ! -d /tmp/bash ]; then - git clone https://github.com/bminor/bash.git /tmp/bash -fi - - -pushd /tmp/bash -if [ ! -f "/tmp/bash/bash" ]; then - ./configure --without-bash-malloc --enable-static-link --host=aarch64-linux-gnu CC=aarch64-linux-gnu-gcc - make -fi - -if [ ! -f "$MOUNT/bin/bash" ]; then - sudo mkdir -p "$MOUNT/bin" - sudo cp bash "$MOUNT/bin" -fi -popd - -# busybox -- I couldn't get this to build. I ended up restoring to a third-party static binary which isn't ideal but it get's things running. -pushd "/tmp" -if [ ! -f "$MOUNT/bin/busybox-aarch64-linux-gnu" ]; then - wget https://github.com/shutingrz/busybox-static-binaries-fat/raw/refs/heads/main/busybox-aarch64-linux-gnu - chmod +x busybox-aarch64-linux-gnu - sudo cp busybox-aarch64-linux-gnu "$MOUNT/bin" -fi -popd - -sudo mkdir -p "$MOUNT/dev" - -if mountpoint -q "$MOUNT"; then - umount "$MOUNT" -fi diff --git a/qemu-runner.sh b/qemu-runner.sh deleted file mode 100755 index 202d4ca..0000000 --- a/qemu-runner.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -e - -ELF="$1" -BIN="${ELF%.elf}.bin" - -./mkrootfs-aarch64.sh - -# Convert to binary format -aarch64-none-elf-objcopy -O binary "$ELF" "$BIN" -qemu-system-aarch64 -M virt,gic-version=3 -initrd test.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$BIN" diff --git a/scripts/build-deps.sh b/scripts/build-deps.sh new file mode 100755 index 0000000..c413827 --- /dev/null +++ b/scripts/build-deps.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +base="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )" + +mkdir -p "$base/build/bin" +rm -f "$base/build/bin"/* + +pushd "$base/build" &>/dev/null || exit 1 + +if [ ! -f "aarch64-linux-musl-cross.tgz" ] +then + wget https://musl.cc/aarch64-linux-musl-cross.tgz + tar -xzf aarch64-linux-musl-cross.tgz +fi + +popd &>/dev/null || exit 1 + +build=${build:-$(ls $base/scripts/deps)} + +export PATH="$base/build/aarch64-linux-musl-cross/bin:$PATH" + +for script in "$base/scripts/deps/"* +do + [ -e "$script" ] || continue # skip if no file exists + [ -x "$script" ] || continue # skip if not executable + + filename=$(basename "$script") + + if [[ "$filename" == _* ]] + then + echo "Skipping: $filename" + continue + fi + + # skip if not in build list + if ! grep -qw "$filename" <<< "$build"; + then + echo "Skipping: $filename" + continue + fi + + echo "Preparing: $filename" + + # make sure each script is run in the base directory + pushd "$base" &>/dev/null || exit 1 + bash "$script" + popd &>/dev/null || exit 1 +done diff --git a/scripts/create-image.sh b/scripts/create-image.sh new file mode 100755 index 0000000..6748217 --- /dev/null +++ b/scripts/create-image.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +base="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )" +pushd "$base" &>/dev/null || exit 1 + +img="$base/moss.img" +mount="$base/build/mount" + +mkdir -p "$mount" + +dd if=/dev/zero of="$img" bs=1M count=128 +mkfs.vfat -F 32 "$img" + +if ! mountpoint -q "$mount"; then + mount -o loop "$img" "$mount" +fi + +mkdir -p "$mount/bin" +mkdir -p "$mount/dev" + +cp "$base/build/bin"/* "$mount/bin" + +if mountpoint -q "$mount"; then + umount "$mount" +fi +popd &>/dev/null || exit 1 \ No newline at end of file diff --git a/scripts/deps/README.md b/scripts/deps/README.md new file mode 100644 index 0000000..1d9b1ff --- /dev/null +++ b/scripts/deps/README.md @@ -0,0 +1,6 @@ +Every executable file in this directory is executed by `build-deps.sh`. + +When writing a new script you can assume you are in the root directory of the project. + +Downloads, git repos, etc. should be placed in the `build` directory. +The built binaries should be placed in the `build/bin` directory. \ No newline at end of file diff --git a/scripts/deps/bash b/scripts/deps/bash new file mode 100755 index 0000000..1f7b004 --- /dev/null +++ b/scripts/deps/bash @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +bash_repo="${bash_repo:-https://git.savannah.gnu.org/git/bash.git}" +bash_tag="${bash_tag:-bash-5.3}" +stdlib="${stdlib:-musl}" + +pushd "build" &>/dev/null || exit 1 + +if [ ! -d "bash" ]; then + git clone --depth 1 --branch "$bash_tag" "$bash_repo" "bash" +else + pushd "bash" &>/dev/null || exit 1 + git pull + popd &>/dev/null || exit 1 +fi + +pushd "bash" &>/dev/null || exit 1 +./configure --without-bash-malloc --enable-static-link --host="aarch64-linux-$stdlib" CC="aarch64-linux-$stdlib-gcc" +make +mv bash ../bin/bash +popd &>/dev/null || exit 1 + +popd &>/dev/null || exit 1 \ No newline at end of file diff --git a/scripts/deps/busybox b/scripts/deps/busybox new file mode 100755 index 0000000..f1fb9d2 --- /dev/null +++ b/scripts/deps/busybox @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +# busybox -- I couldn't get this to build. I ended up restoring to a third-party static binary which isn't ideal but it get's things running. +pushd "build" &>/dev/null || exit 1 +wget https://github.com/shutingrz/busybox-static-binaries-fat/raw/refs/heads/main/busybox-aarch64-linux-gnu +chmod +x busybox-aarch64-linux-gnu +mv busybox-aarch64-linux-gnu bin/busybox + +popd &>/dev/null || exit 1 + +popd &>/dev/null || exit 1 \ No newline at end of file diff --git a/scripts/qemu-runner.sh b/scripts/qemu-runner.sh new file mode 100755 index 0000000..72b14bb --- /dev/null +++ b/scripts/qemu-runner.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -e + +base="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )" + +elf="$1" +bin="${elf%.elf}.bin" + +# Convert to binary format +aarch64-none-elf-objcopy -O binary "$elf" "$bin" +qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" diff --git a/src/arch/arm64/boot/mod.rs b/src/arch/arm64/boot/mod.rs index 762f7c7..362a1d7 100644 --- a/src/arch/arm64/boot/mod.rs +++ b/src/arch/arm64/boot/mod.rs @@ -126,7 +126,7 @@ fn arch_init_stage2(frame: *mut ExceptionState) -> *mut ExceptionState { cpu_messenger_init(cpu_count()); kmain( - "--init=/bin/sh --rootfs=fat32fs --automount=/dev,devfs".to_string(), + "--init=/bin/bash --rootfs=fat32fs --automount=/dev,devfs".to_string(), frame, ); diff --git a/src/main.rs b/src/main.rs index e560b4d..2aa7878 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,7 +95,7 @@ async fn launch_init(opts: KOptions) { let mount_point = VFS .resolve_path(path, VFS.root_inode()) .await - .unwrap_or_else(|e| panic!("Could not find automount path: {e}")); + .unwrap_or_else(|e| panic!("Could not find automount path: {}. {e}", path.as_str())); VFS.mount(mount_point, fs, None) .await