diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..75f3c33 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +nbuild = "run --manifest-path nbuild/Cargo.toml --" diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 0000000..6175d51 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,14 @@ +name: Clippy + +on: [push, pull_request] + +jobs: + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: rustup component add clippy + - run: cargo nbuild clippy + diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index ac616f8..57ae7a3 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -3,15 +3,11 @@ name: Format on: [push, pull_request] jobs: - run_cargo_fmt: - name: Run cargo fmt + format: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: submodules: true - - name: Add Tool - run: rustup component add rustfmt - - name: Check Format - run: cargo fmt -- --check + - run: rustup component add rustfmt + - run: cargo nbuild format --check diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4ecb7e5..41541fc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,78 +3,107 @@ name: Build on: [push, pull_request] jobs: - build: - name: Build (and Release) + embedded-binaries: runs-on: ubuntu-latest + strategy: + matrix: + target: [thumbv6m-none-eabi, thumbv7em-none-eabi, thumbv8m.main-none-eabi] + start_address: [0x0802_0000, 0x1002_0000] steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: submodules: true - - - name: Check Syntax - run: | - cargo check - - - name: Test - run: | - cargo test --lib - - - name: Install Targets and Tools - run: | - rustup toolchain install stable --profile minimal --no-self-update - rustup default stable - rustup target add thumbv7em-none-eabi - rustup target add thumbv7m-none-eabi - rustup target add thumbv6m-none-eabi - rustup component add llvm-tools-preview - echo CARGO_INCREMENTAL=0 >> $GITHUB_ENV - echo CARGO_TERM_COLOR=always >> $GITHUB_ENV - - - name: Install tools - uses: taiki-e/install-action@v2 + - run: rustup target add ${{ matrix.target }} + - run: rustup component add llvm-tools-preview + - run: cargo nbuild binary --target=${{ matrix.target }} --start-address=${{ matrix.start_address }} + - uses: actions/upload-artifact@v4 + if: ${{success()}} with: - tool: cargo-binutils@0.3.6 - - - name: Install ROMFS tools - run: | - cargo install neotron-romfs-lsfs - cargo install neotron-romfs-mkfs - - - name: Build - run: | - ./build.sh --verbose - - - name: Upload Artifacts - uses: actions/upload-artifact@v4 + name: ${{ matrix.target }}-${{ matrix.start_address }}-binary + if-no-files-found: error + path: | + ./target/${{ matrix.target }}/release/neotron-os + ./target/${{ matrix.target }}/release/neotron-os.bin + ./target/${{ matrix.target }}/release/romfs.bin + x64_64-unknown-linux-gnu-library: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: cargo nbuild library + - uses: actions/upload-artifact@v4 if: ${{success()}} with: - name: Artifacts + name: x64_64-unknown-linux-gnu-library if-no-files-found: error path: | - ./release/ - - - name: Upload files to Release - if: github.event_name == 'push' && startswith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v1 + ./target/release/libneotron_os.so + x86_64-pc-windows-msvc-library: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: cargo nbuild library + - uses: actions/upload-artifact@v4 + if: ${{success()}} + with: + name: x86_64-pc-windows-msvc-library + if-no-files-found: error + path: | + ./target/release/neotron_os.dll + ./target/release/neotron_os.dll.exp + ./target/release/neotron_os.dll.lib + ./target/release/neotron_os.pdb + aarch64-apple-darwin-library: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: cargo nbuild library + - uses: actions/upload-artifact@v4 + if: ${{success()}} + with: + name: aarch64-apple-darwin-library + if-no-files-found: error + path: | + ./target/release/libneotron_os.dylib + run-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - run: cargo nbuild test + preview-release: + runs-on: ubuntu-latest + needs: [embedded-binaries, x64_64-unknown-linux-gnu-library, x86_64-pc-windows-msvc-library, aarch64-apple-darwin-library, run-tests] + steps: + - run: mkdir ./release + - uses: actions/download-artifact@v4 + with: + path: ./release-${{ github.ref_name }} + - run: ls -lR ./release-${{ github.ref_name }} + - run: zip -r ./release-${{ github.ref_name }}.zip ./release-${{ github.ref_name }} + - uses: actions/upload-artifact@v4 + if: ${{success()}} + with: + name: release + if-no-files-found: error + path: | + ./release-${{ github.ref_name }}.zip + release: + runs-on: ubuntu-latest + needs: [preview-release] + if: github.event_name == 'push' && startswith(github.ref, 'refs/tags/') + steps: + - uses: actions/download-artifact@v4 + with: + name: release + path: . + - uses: softprops/action-gh-release@v1 with: files: | - ./release/thumbv6m-none-eabi-flash0002-libneotron_os.bin - ./release/thumbv6m-none-eabi-flash0002-libneotron_os.elf - ./release/thumbv6m-none-eabi-flash0802-libneotron_os.bin - ./release/thumbv6m-none-eabi-flash0802-libneotron_os.elf - ./release/thumbv6m-none-eabi-flash1002-libneotron_os.bin - ./release/thumbv6m-none-eabi-flash1002-libneotron_os.elf - ./release/thumbv7em-none-eabi-flash0002-libneotron_os.bin - ./release/thumbv7em-none-eabi-flash0002-libneotron_os.elf - ./release/thumbv7em-none-eabi-flash0802-libneotron_os.bin - ./release/thumbv7em-none-eabi-flash0802-libneotron_os.elf - ./release/thumbv7em-none-eabi-flash1002-libneotron_os.bin - ./release/thumbv7em-none-eabi-flash1002-libneotron_os.elf - ./release/thumbv7m-none-eabi-flash0002-libneotron_os.bin - ./release/thumbv7m-none-eabi-flash0002-libneotron_os.elf - ./release/thumbv7m-none-eabi-flash0802-libneotron_os.bin - ./release/thumbv7m-none-eabi-flash0802-libneotron_os.elf - ./release/thumbv7m-none-eabi-flash1002-libneotron_os.bin - ./release/thumbv7m-none-eabi-flash1002-libneotron_os.elf - ./release/x86_64-unknown-linux-gnu-libneotron_os.so + ./release-${{ github.ref_name }}.zip diff --git a/.gitignore b/.gitignore index dd9db28..1726119 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/nbuild/target /target **/*.rs.bk /release diff --git a/.vscode/settings.json b/.vscode/settings.json index d07faa6..b342773 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.cargo.target": "thumbv6m-none-eabi" + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "./nbuild/Cargo.toml" + ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 29b287c..f9116c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "arrayvec" diff --git a/Cargo.toml b/Cargo.toml index 9fca006..2b7a204 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,9 @@ members = [ "utilities/flames", ] resolver = "2" +exclude = [ + "nbuild" +] [workspace.dependencies] neotron-sdk = "0.2.0" diff --git a/README.md b/README.md index 176cdde..b96272d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ This OS is a work in progress. We intend to support: * [x] Executing applications from RAM * [x] Applications can print to stdout * [x] Applications can read from stdin - * [ ] Applications can open/close/read/write files + * [x] Applications can open/close/read files + * [ ] Applications can write to files * [x] MBR/FAT32 formatted block devices * [x] Read blocks * [x] Directory listing of / @@ -22,6 +23,7 @@ This OS is a work in progress. We intend to support: * [ ] Delete files * [ ] Change directory * [x] Load ELF binaries from disk +* [x] Load ELF binaries from ROM * [x] Changing text modes * [ ] Basic networking * [x] Music playback @@ -35,55 +37,30 @@ Your board will need an appropriate Neotron BIOS installed, and you need to have OpenOCD or some other programming tool running for your particular board. See your BIOS instructions for more details. -We compile one version of Neotron OS, but we link it three times to produce -three different binaries: +Building Neotron OS is handled by the `nbuild` tool, in this repository. Run `cargo nbuild help` for more information. -* `flash0002` - is linked to run from address `0x0002_0000` -* `flash1002` - is linked to run from address `0x1002_0000` -* `flash0802` - is linked to run from address `0x0802_0000` +To make an image for a board like the Neotron Pico, you want to run `cargo nbuild binary`. By default this will produce a `thumbv6m-none-eabi` image linked to run at address `0x1002_0000`, with a ROMFS containing various utilities, which is what you need on a Neotron Pico. Your BIOS should tell you if you need to change these options, and how to load the resulting image onto your system. ```console -$ git clone https://github.com/neotron-compute/Neotron-OS.git -$ cd Neotron-OS -$ cargo build --target thumbv6m-none-eabi --release --bins -$ ls ./target/thumbv6m-none-eabi/release/flash*02 -./target/thumbv6m-none-eabi/release/flash0002 ./target/thumbv6m-none-eabi/release/flash0802 ./target/thumbv6m-none-eabi/release/flash1002 +$ cargo nbuild binary +... +$ ls ./target/thumbv6m-none-eabi/release +build/ examples/ flames.d libflames.d libneotron_os.d neotron-os neotron-os.d +deps/ flames incremental/ libflames.rlib libneotron_os.rlib neotron-os.bin romfs.bin ``` -Your BIOS should tell you which one you want and how to load it onto your system. +Here: -You can also build a *shared object* to load into a Windows/Linux/macOS application. +* `romfs.bin` is the raw ROMFS image +* `neotron-os` is an ELF file containing the OS and the ROMFS image +* `neotron-os.bin` is an raw binary copy of the contents of the ELF file -```console -$ cargo build --lib -$ ls ./target/debug/*.so -./target/debug/libneotron_os.so -``` - -If you want to include a ROMFS, you need to: - -```bash -cargo install neotron-romfs-lsfs -cargo install neotron-romfs-mkfs -cargo install cargo-binutils -``` - -A bunch of utilities are supplied in the [`utilities`](./utilities/) folder. Build them all, and make a ROMFS image, then build the OS with the `ROMFS_PATH` environment variable set. - -```bash -TGT=$(pwd)/target/thumbv6m-none-eabi/release -cargo build --bin flames --target thumbv6m-none-eabi --release -rust-strip ${TGT}/flames -o ${TGT}/flames.elf -neotron-romfs-mkfs ${TGT}/flames.elf > ${TGT}/romfs.img -ROMFS_PATH=${TGT}/romfs.img cargo build --bin flash1002 --target thumbv6m-none-eabi --release -``` - -The OS will then include the ROMFS image, which you can access with the `rom` command. +When the OS is running, programs in the ROMFS can be loaded with: ```text > rom -flames.elf (14212 bytes) -> rom flames.elf +flames (14212 bytes) +> rom flames Loading 4256 bytes to 0x20001000 Loading 532 bytes to 0x200020a0 Loading 4908 bytes to 0x200022b4 @@ -93,6 +70,15 @@ Loading 4908 bytes to 0x200022b4 A better UI for loading files from ROM is being planned (maybe we should have drive letters, and the ROM can be `R:`). +You can also build a *shared object* to load into a Windows/Linux/macOS application, like [Neotron Desktop BIOS](https://github.com/neotron-compute/neotron-desktop-bios): + +```console +$ cargo nbuild library +... +$ ls ./target/debug/*.so +./target/debug/libneotron_os.so +``` + ## Changelog See [`CHANGELOG.md`](./CHANGELOG.md) @@ -100,7 +86,7 @@ See [`CHANGELOG.md`](./CHANGELOG.md) ## Licence ```text -Neotron-OS Copyright (c) Jonathan 'theJPster' Pallant and The Neotron Developers, 2023 +Copyright (c) 2019-2024 Jonathan 'theJPster' Pallant and The Neotron Developers 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/build.sh b/build.sh deleted file mode 100755 index 2ac6939..0000000 --- a/build.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - -RELEASE_DIR=${SCRIPT_DIR}/release - -mkdir -p ${RELEASE_DIR} - -# Build the embedded binaries for each core type and each flash layout -for TARGET_ARCH in thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi; do - echo "TARGET is ${TARGET_ARCH}" - # Rename our utilities to have an ELF extension - for utility in flames; do - ( cd ${SCRIPT_DIR} && cargo build $* --release --target=${TARGET_ARCH} --bin ${utility} ) - rust-strip ${SCRIPT_DIR}/target/${TARGET_ARCH}/release/${utility} -o ${SCRIPT_DIR}/target/${TARGET_ARCH}/release/${utility}.elf - done - # Make a ROMFS - export ROMFS_PATH=${SCRIPT_DIR}/target/${TARGET_ARCH}/release/romfs.img - neotron-romfs-mkfs \ - ${SCRIPT_DIR}/target/${TARGET_ARCH}/release/flames.elf \ - > ${ROMFS_PATH} - neotron-romfs-lsfs ${ROMFS_PATH} - # Build the OS again, with the new ROMFS - for BINARY in flash0002 flash0802 flash1002; do - echo "BINARY is ${BINARY}" - ( cd ${SCRIPT_DIR}/neotron-os && cargo build $* --release --target=${TARGET_ARCH} --bin ${BINARY} ) - # objcopy would do the build for us first, but it doesn't have good build output - rust-objcopy -O binary ${SCRIPT_DIR}/target/${TARGET_ARCH}/release/${BINARY} ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.bin - # Keep the ELF file too (for debugging) - cp ${SCRIPT_DIR}/target/${TARGET_ARCH}/release/${BINARY} ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.elf - done -done - -# Build the host version -echo "Building HOST" -( cd ${SCRIPT_DIR} && cargo build --verbose --lib --release --target=x86_64-unknown-linux-gnu ) -cp ${SCRIPT_DIR}/target/x86_64-unknown-linux-gnu/release/libneotron_os.so ${RELEASE_DIR}/x86_64-unknown-linux-gnu-libneotron_os.so diff --git a/nbuild/Cargo.lock b/nbuild/Cargo.lock new file mode 100644 index 0000000..7787e26 --- /dev/null +++ b/nbuild/Cargo.lock @@ -0,0 +1,303 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "num-traits", +] + +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "nbuild" +version = "0.1.0" +dependencies = [ + "chrono", + "clap", + "embedded-io", + "neotron-api", + "neotron-romfs", +] + +[[package]] +name = "neotron-api" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d6c96706b6f3ec069abfb042cadfd2d701980fa4940f407c0bc28ee1e1c493" +dependencies = [ + "bitflags", + "neotron-ffi", +] + +[[package]] +name = "neotron-ffi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37886e73d87732421aaf5da617eead9d69a7daf6b0d059780f76157d9ce5372" + +[[package]] +name = "neotron-romfs" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f7987e34f25f780b5dd5a22b5da7ce9a566d93b8f608f78293a170f35f024c7" +dependencies = [ + "embedded-io", + "neotron-api", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/nbuild/Cargo.toml b/nbuild/Cargo.toml new file mode 100644 index 0000000..99fc2d8 --- /dev/null +++ b/nbuild/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "nbuild" +version = "0.1.0" +edition = "2021" +authors = [ + "Jonathan 'theJPster' Pallant ", + "The Neotron Developers" +] +description = "The Neotron Operating System Build System" +license = "GPL-3.0-or-later" +readme = "README.md" +repository = "https://github.com/neotron-compute/Neotron-OS" + +[dependencies] +chrono = { version = "0.4.39", default-features = false, features = ["std"] } +clap = { version = "4.5.23", features = ["derive"] } +embedded-io = { version = "0.6.1", features = ["std"] } +neotron-api = "0.2.0" +neotron-romfs = "2.0" diff --git a/nbuild/README.md b/nbuild/README.md new file mode 100644 index 0000000..3f99f91 --- /dev/null +++ b/nbuild/README.md @@ -0,0 +1,12 @@ +# nbuild - the Neotron OS Build System + +Building Neotron OS involves: + +* Compiling the Neotron OS source code +* Compiling and linking multiple Neotron OS utilities +* Assembling the utilities into a ROMFS image +* Linking the Neotron OS object code, including the ROMFS image + +This utility automates that process. + +Run `cargo nbuild --help` from the top level of the checkout for more information. diff --git a/nbuild/src/lib.rs b/nbuild/src/lib.rs new file mode 100644 index 0000000..9416b5f --- /dev/null +++ b/nbuild/src/lib.rs @@ -0,0 +1,148 @@ +//! Utility functions + +/// The ways that spawning `cargo` can fail +#[derive(Debug)] +pub enum ProcessError { + SpawnError(std::io::Error), + RunError(std::process::ExitStatus), +} + +impl std::fmt::Display for ProcessError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProcessError::SpawnError(error) => write!(f, "Failed to spawn command: {}", error), + ProcessError::RunError(exit_status) => write!( + f, + "Failed to complete command ({}). There should be an error above", + exit_status + ), + } + } +} + +/// The kinds of package we have +#[derive(Debug, PartialEq, Eq)] +pub enum PackageKind { + Os, + Utility, + NBuild, +} + +/// Describes a package in this repository +#[derive(Debug)] +pub struct Package { + pub name: &'static str, + pub path: &'static std::path::Path, + pub kind: PackageKind, + pub testable: bool, + pub output_template: Option<&'static str>, +} + +impl Package { + pub fn output(&self, target: &str, profile: &str) -> Option { + self.output_template + .map(|s| s.replace("{target}", target).replace("{profile}", profile)) + } +} + +/// Parse an integer, with an optional `0x` prefix. +/// +/// Underscores are ignored. +/// +/// ```rust +/// # use nbuild::parse_int; +/// assert_eq!(parse_int("0x0000_000A"), Ok(10)); +/// assert_eq!(parse_int("000_10"), Ok(10)); +/// ``` +pub fn parse_int(input: S) -> Result +where + S: AsRef, +{ + let input = input.as_ref().replace('_', ""); + if let Some(suffix) = input.strip_prefix("0x") { + u32::from_str_radix(suffix, 16) + } else { + input.parse() + } +} + +/// Runs cargo +pub fn cargo

( + commands: &[&str], + target: Option<&str>, + manifest_path: P, +) -> Result<(), ProcessError> +where + P: AsRef, +{ + cargo_with_env(commands, target, manifest_path, &[]) +} + +/// Runs cargo with extra environment variables +pub fn cargo_with_env

( + commands: &[&str], + target: Option<&str>, + manifest_path: P, + environment: &[(&'static str, String)], +) -> Result<(), ProcessError> +where + P: AsRef, +{ + let mut command_line = std::process::Command::new("cargo"); + command_line.stdout(std::process::Stdio::inherit()); + command_line.stderr(std::process::Stdio::inherit()); + command_line.args(commands); + if let Some(target) = target { + command_line.arg("--target"); + command_line.arg(target); + } + command_line.arg("--manifest-path"); + command_line.arg(manifest_path.as_ref()); + for (k, v) in environment.into_iter() { + command_line.env(k, v); + } + + println!("Running: {:?}", command_line); + + let output = command_line.output().map_err(ProcessError::SpawnError)?; + + if output.status.success() { + Ok(()) + } else { + Err(ProcessError::RunError(output.status)) + } +} + +/// Make a binary version of an ELF file +pub fn make_bin

(path: P) -> Result +where + P: AsRef, +{ + let path = path.as_ref(); + println!("Making binary of: {}", path.display()); + let output = std::process::Command::new("rustc") + .arg("--print") + .arg("target-libdir") + .output() + .expect("Failed to run rustc --print target-libdir"); + let sysroot = String::from_utf8(output.stdout).expect("sysroot path isn't UTF-8"); + let sysroot: std::path::PathBuf = sysroot.trim().into(); + let mut objcopy = sysroot.clone(); + objcopy.pop(); + objcopy.push("bin"); + objcopy.push("llvm-objcopy"); + let mut command_line = std::process::Command::new(objcopy); + command_line.args(["-O", "binary"]); + command_line.arg(path); + let output_file = path.with_extension("bin"); + command_line.arg(&output_file); + println!("Running: {:?}", command_line); + let output = command_line.output().map_err(ProcessError::SpawnError)?; + if output.status.success() { + Ok(output_file) + } else { + Err(ProcessError::RunError(output.status)) + } +} + +// End of file diff --git a/nbuild/src/main.rs b/nbuild/src/main.rs new file mode 100644 index 0000000..90dac30 --- /dev/null +++ b/nbuild/src/main.rs @@ -0,0 +1,280 @@ +//! A series of utilities for building Neotron OS + +use clap::{Parser, Subcommand}; + +#[derive(Debug, Subcommand)] +enum Commands { + /// Builds the OS and the ROMFS + Binary { + /// The start address in Flash where Neotron OS should live + #[clap(long, default_value = "0x1002_0000")] + start_address: String, + /// The target we're building Neotron OS for + #[clap(long, default_value = "thumbv6m-none-eabi")] + target: String, + }, + /// Builds the OS as a library, for the native machine + Library { + /// The target we're building Neotron OS for + #[clap(long)] + target: Option, + }, + /// Handles formatting of the Neotron OS source code + Format { + /// Whether to just check the formatting + #[clap(long)] + check: bool, + }, + /// Checks the Neotron OS source code using clippy + Clippy, + /// Runs any tests + Test, +} + +/// A simple utility for building Neotron OS and a suitable ROMFS image +#[derive(Debug, Parser)] +#[clap(name = "nbuild", version = "0.1.0", author = "The Neotron Developers")] +pub struct NBuildApp { + /// The task to perform + #[command(subcommand)] + command: Option, +} + +fn packages() -> Vec { + vec![ + nbuild::Package { + name: "nbuild", + path: std::path::Path::new("./nbuild/Cargo.toml"), + output_template: None, + kind: nbuild::PackageKind::NBuild, + testable: true, + }, + nbuild::Package { + name: "flames", + path: std::path::Path::new("./utilities/flames/Cargo.toml"), + output_template: Some("./target/{target}/{profile}/flames"), + kind: nbuild::PackageKind::Utility, + testable: false, + }, + nbuild::Package { + name: "Neotron OS", + path: std::path::Path::new("./neotron-os/Cargo.toml"), + output_template: Some("./target/{target}/{profile}/neotron-os"), + kind: nbuild::PackageKind::Os, + testable: false, + }, + ] +} + +fn main() { + println!("Neotron OS nbuild tool"); + let args = NBuildApp::parse(); + let packages = packages(); + match args.command { + None => { + // No command given + println!("No command given. Try `cargo nbuild help`."); + std::process::exit(1); + } + Some(Commands::Binary { + start_address, + target, + }) => { + binary(&packages, &start_address, &target); + } + Some(Commands::Library { target }) => library(&packages, target.as_deref()), + Some(Commands::Format { check }) => format(&packages, check), + Some(Commands::Clippy) => clippy(&packages), + Some(Commands::Test) => test(&packages), + } +} + +/// Builds the utility and OS packages as binaries +fn binary(packages: &[nbuild::Package], start_address: &str, target: &str) { + use chrono::{Datelike, Timelike}; + + let mut is_error = false; + let Ok(start_address) = nbuild::parse_int(start_address) else { + eprintln!("{:?} was not a valid integer", start_address); + std::process::exit(1); + }; + + let mut romfs_entries = Vec::new(); + // Build utilities + for package in packages + .iter() + .filter(|p| p.kind == nbuild::PackageKind::Utility) + { + println!( + "Cross-compiling {}, using target {:?}", + package.name, target + ); + if let Err(e) = nbuild::cargo(&["build", "--release"], Some(target), package.path) { + eprintln!("Build of {} failed: {}", package.name, e); + is_error = true; + } + let package_output = package + .output(target, "release") + .expect("utilties should have an output"); + let contents = match std::fs::read(&package_output) { + Ok(contents) => contents, + Err(e) => { + eprintln!("Reading of {} failed: {}", package_output, e); + continue; + } + }; + let ctime = std::time::SystemTime::now(); + let ctime = chrono::DateTime::::from(ctime); + romfs_entries.push(neotron_romfs::Entry { + metadata: neotron_romfs::EntryMetadata { + file_name: package.name, + ctime: neotron_api::file::Time { + year_since_1970: (ctime.year() - 1970) as u8, + zero_indexed_month: ctime.month0() as u8, + zero_indexed_day: ctime.day0() as u8, + hours: ctime.hour() as u8, + minutes: ctime.minute() as u8, + seconds: ctime.second() as u8, + }, + file_size: contents.len() as u32, + }, + contents, + }); + } + + // Build ROMFS + let mut buffer = Vec::new(); + let _size = match neotron_romfs::RomFs::construct_into(&mut buffer, &romfs_entries) { + Ok(size) => size, + Err(e) => { + eprintln!("Making ROMFS failed: {:?}", e); + std::process::exit(1); + } + }; + let mut romfs_path = std::path::PathBuf::new(); + romfs_path.push(std::env::current_dir().expect("We have no CWD?")); + romfs_path.push("target"); + romfs_path.push(target); + romfs_path.push("release"); + romfs_path.push("romfs.bin"); + if let Err(e) = std::fs::write(&romfs_path, &buffer) { + eprintln!("Writing ROMFS to {} failed: {:?}", romfs_path.display(), e); + std::process::exit(1); + } + println!("Built ROMFS at {}", romfs_path.display()); + + // Build OS + for package in packages + .iter() + .filter(|p| p.kind == nbuild::PackageKind::Os) + { + println!( + "Cross-compiling {}, using start address 0x{:08x} and target {:?}", + package.name, start_address, target + ); + let environment = [ + ( + "NEOTRON_OS_START_ADDRESS", + format!("0x{:08x}", start_address), + ), + ("ROMFS_PATH", romfs_path.to_string_lossy().to_string()), + ]; + if let Err(e) = nbuild::cargo_with_env( + &["build", "--release"], + Some(target), + package.path, + &environment, + ) { + eprintln!("Build of {} failed: {}", package.name, e); + is_error = true; + } + let package_output = package + .output(target, "release") + .expect("PackageKind::Os should always have output"); + if let Err(e) = nbuild::make_bin(&package_output) { + eprintln!("objcopy of {} failed: {}", package_output, e); + is_error = true; + } + } + if is_error { + std::process::exit(1); + } +} + +/// Builds the OS packages as a library +fn library(packages: &[nbuild::Package], target: Option<&str>) { + let mut is_error = false; + println!( + "Compiling Neotron OS library, using target {:?}", + target.unwrap_or("native") + ); + for package in packages + .iter() + .filter(|p| p.kind == nbuild::PackageKind::Os) + { + println!( + "Compiling {}, target {:?}", + package.name, + target.unwrap_or("native") + ); + if let Err(e) = nbuild::cargo(&["build", "--release", "--lib"], target, package.path) { + eprintln!("Build of {} failed: {}", package.name, e); + is_error = true; + } + } + if is_error { + std::process::exit(1); + } +} + +/// Runs `cargo fmt` over all the packages +fn format(packages: &[nbuild::Package], check: bool) { + let mut is_error = false; + let commands = if check { + vec!["fmt", "--check"] + } else { + vec!["fmt"] + }; + for package in packages.iter() { + println!("Formatting {}", package.name); + if let Err(e) = nbuild::cargo(&commands, None, package.path) { + eprintln!("Format failed: {}", e); + is_error = true; + } + } + if is_error { + std::process::exit(1); + } +} + +/// Runs `cargo clippy` over all the packages +fn clippy(packages: &[nbuild::Package]) { + let mut is_error = false; + for package in packages.iter() { + println!("Linting {} with clippy", package.name); + if let Err(e) = nbuild::cargo(&["clippy"], None, package.path) { + eprintln!("Lint failed: {}", e); + is_error = true; + } + } + if is_error { + std::process::exit(1); + } +} + +/// Runs `cargo test` over all the packages +fn test(packages: &[nbuild::Package]) { + let mut is_error = false; + for package in packages.iter().filter(|p| p.testable) { + println!("Testing {}", package.name); + if let Err(e) = nbuild::cargo(&["test"], None, package.path) { + eprintln!("Test failed: {}", e); + is_error = true; + } + } + if is_error { + std::process::exit(1); + } +} + +// End of file diff --git a/neotron-os/Cargo.toml b/neotron-os/Cargo.toml index ab7dc16..77c373f 100644 --- a/neotron-os/Cargo.toml +++ b/neotron-os/Cargo.toml @@ -12,17 +12,7 @@ readme = "README.md" repository = "https://github.com/neotron-compute/Neotron-OS" [[bin]] -name = "flash1002" -test = false -bench = false - -[[bin]] -name = "flash0802" -test = false -bench = false - -[[bin]] -name = "flash0002" +name = "neotron-os" test = false bench = false diff --git a/neotron-os/build.rs b/neotron-os/build.rs index a91e548..f56cbe0 100644 --- a/neotron-os/build.rs +++ b/neotron-os/build.rs @@ -1,13 +1,14 @@ use std::io::prelude::*; +const LINKER_SCRIPT: &str = "neotron-os-arm.ld"; + fn main() { - if let Ok("none") = std::env::var("CARGO_CFG_TARGET_OS").as_deref() { - copy_linker_script("neotron-flash-1002.ld"); - println!("cargo::rustc-link-arg-bin=flash1002=-Tneotron-flash-1002.ld"); - copy_linker_script("neotron-flash-0802.ld"); - println!("cargo::rustc-link-arg-bin=flash0802=-Tneotron-flash-0802.ld"); - copy_linker_script("neotron-flash-0002.ld"); - println!("cargo::rustc-link-arg-bin=flash0002=-Tneotron-flash-0002.ld"); + if Ok("none") == std::env::var("CARGO_CFG_TARGET_OS").as_deref() { + let start_address = std::env::var("NEOTRON_OS_START_ADDRESS"); + let start_address = start_address.as_deref().unwrap_or("0x10020000"); + copy_linker_script(start_address); + println!("cargo::rustc-link-arg-bin=neotron-os=-T{}", LINKER_SCRIPT); + println!("cargo::rerun-if-env-changed=NEOTRON_OS_START_ADDRESS"); } if let Ok(cmd_output) = std::process::Command::new("git") @@ -35,21 +36,23 @@ fn main() { println!("cargo::rustc-link-lib=dylib=msvcrt"); } - if option_env!("ROMFS_PATH").is_some() { + if let Some(path) = option_env!("ROMFS_PATH") { println!("cargo::rustc-cfg=romfs_enabled=\"yes\""); println!("cargo::rerun-if-env-changed=ROMFS_PATH"); + println!("cargo::rerun-if-changed={}", path); } println!("cargo::rustc-check-cfg=cfg(romfs_enabled, values(\"yes\"))"); } /// Put the given script in our output directory and ensure it's on the linker /// search path. -fn copy_linker_script(path: &str) { +fn copy_linker_script(start_address: &str) { let out = &std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap()); - let contents = std::fs::read_to_string(path).expect("loading ld script"); - std::fs::File::create(out.join(path)) + let contents = std::fs::read_to_string(LINKER_SCRIPT).expect("loading ld script"); + let patched = contents.replace("${{start_address}}", start_address); + std::fs::File::create(out.join(LINKER_SCRIPT)) .unwrap() - .write_all(contents.as_bytes()) + .write_all(patched.as_bytes()) .unwrap(); println!("cargo::rustc-link-search={}", out.display()); } diff --git a/neotron-os/neotron-flash-0802.ld b/neotron-os/neotron-flash-0802.ld deleted file mode 100644 index 3a961ab..0000000 --- a/neotron-os/neotron-flash-0802.ld +++ /dev/null @@ -1,159 +0,0 @@ -/* # Developer notes - -- Symbols that start with a double underscore (__) are considered "private" - -- Symbols that start with a single underscore (_) are considered "semi-public"; they can be - overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { - static mut __sbss }`). - -- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a - symbol if not dropped if it appears in or near the front of the linker arguments and "it's not - needed" by any of the preceding objects (linker arguments) - -- `PROVIDE` is used to provide default values that can be overridden by a user linker script - -- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* - the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization - routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see - "Address (..) is out of bounds" in the disassembly produced by `objdump`. -*/ - -/* Provides information about the memory layout of the device */ -MEMORY -{ - /* The first 128 KiB is for the BIOS. We get the rest. */ - FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 256K - /* - * We get the bottom 4KB of RAM. Anything above that is for applications - * (up to wherever the BIOS tells us we can use.) - */ - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 4K -} - -/* # Entry point = what the BIOS calls to start the OS */ -ENTRY(os_main); - -/* -Where the Transient Program Area starts. -*/ -_tpa_start = ORIGIN(RAM) + LENGTH(RAM); - -/* # Sections */ -SECTIONS -{ - - /* ## Sections in FLASH */ - .entry_point ORIGIN(FLASH) : - { - KEEP(*(.entry_point)) - } > FLASH - - PROVIDE(_stext = ADDR(.entry_point) + SIZEOF(.entry_point)); - - /* ### .text */ - .text _stext : - { - *(.text .text.*); - *(.HardFaultTrampoline); - *(.HardFault.*); - } > FLASH - - /* ### .rodata */ - .rodata : ALIGN(4) - { - *(.rodata .rodata.*); - - /* 4-byte align the end (VMA) of this section. - This is required by LLD to ensure the LMA of the following .data - section will have the correct alignment. */ - . = ALIGN(4); - } > FLASH - - /* ## Sections in RAM */ - /* ### .data */ - .data : ALIGN(4) - { - . = ALIGN(4); - __sdata = .; - *(.data .data.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __edata = .; - } > RAM AT > FLASH - - /* LMA of .data */ - __sidata = LOADADDR(.data); - - /* ### .bss */ - .bss : ALIGN(4) - { - . = ALIGN(4); - __sbss = .; - *(.bss .bss.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __ebss = .; - } > RAM - - /* ### .uninit */ - .uninit (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - *(.uninit .uninit.*); - . = ALIGN(4); - } > RAM - - /* Place the heap right after `.uninit` */ - . = ALIGN(4); - __sheap = .; - - /* ## .got */ - /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in - the input files and raise an error if relocatable code is found */ - .got (NOLOAD) : - { - KEEP(*(.got .got.*)); - } - - /* ## Discarded sections */ - /DISCARD/ : - { - /* Unused exception related info that only wastes space */ - *(.ARM.exidx); - *(.ARM.exidx.*); - *(.ARM.extab.*); - } -} - -/* Do not exceed this mark in the error messages below | */ -/* # Alignment checks */ -ASSERT(ORIGIN(FLASH) % 4 == 0, " -ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); - -ASSERT(ORIGIN(RAM) % 4 == 0, " -ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); - -ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " -BUG(cortex-m-rt): .data is not 4-byte aligned"); - -ASSERT(__sidata % 4 == 0, " -BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); - -ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " -BUG(cortex-m-rt): .bss is not 4-byte aligned"); - -ASSERT(__sheap % 4 == 0, " -BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); - -/* # Position checks */ - -/* ## .text */ -ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " -ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. -Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); - -/* # Other checks */ -ASSERT(SIZEOF(.got) == 0, " -ERROR(cortex-m-rt): .got section detected in the input object files -Dynamic relocations are not supported. If you are linking to C code compiled using -the 'cc' crate then modify your build script to compile the C code _without_ -the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); -/* Do not exceed this mark in the error messages above | */ diff --git a/neotron-os/neotron-flash-1002.ld b/neotron-os/neotron-flash-1002.ld deleted file mode 100644 index 0ba14c0..0000000 --- a/neotron-os/neotron-flash-1002.ld +++ /dev/null @@ -1,163 +0,0 @@ -/* # Developer notes - -- Symbols that start with a double underscore (__) are considered "private" - -- Symbols that start with a single underscore (_) are considered "semi-public"; they can be - overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { - static mut __sbss }`). - -- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a - symbol if not dropped if it appears in or near the front of the linker arguments and "it's not - needed" by any of the preceding objects (linker arguments) - -- `PROVIDE` is used to provide default values that can be overridden by a user linker script - -- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* - the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization - routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see - "Address (..) is out of bounds" in the disassembly produced by `objdump`. -*/ - -/* Provides information about the memory layout of the device */ -MEMORY -{ - /* The first 128 KiB is for the BIOS. We get the rest. */ - FLASH (rx) : ORIGIN = 0x10020000, LENGTH = 256K - - /* - * The RAM reserved for the OS. Above this is the Transient Program Area. - * - * This is defined by the Neotron specification for a given platform. On this - * Cortex-M based platform, it's the start of Cortex-M SRAM, plus 4 KiB, or - * 0x2000_1000. - */ - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 4K -} - -/* # Entry point = what the BIOS calls to start the OS */ -ENTRY(os_main); - -/* -Where the Transient Program Area starts. -*/ -_tpa_start = ORIGIN(RAM) + LENGTH(RAM); - -/* # Sections */ -SECTIONS -{ - - /* ## Sections in FLASH */ - .entry_point ORIGIN(FLASH) : - { - KEEP(*(.entry_point)) - } > FLASH - - PROVIDE(_stext = ADDR(.entry_point) + SIZEOF(.entry_point)); - - /* ### .text */ - .text _stext : - { - *(.text .text.*); - *(.HardFaultTrampoline); - *(.HardFault.*); - } > FLASH - - /* ### .rodata */ - .rodata : ALIGN(4) - { - *(.rodata .rodata.*); - - /* 4-byte align the end (VMA) of this section. - This is required by LLD to ensure the LMA of the following .data - section will have the correct alignment. */ - . = ALIGN(4); - } > FLASH - - /* ## Sections in RAM */ - /* ### .data */ - .data : ALIGN(4) - { - . = ALIGN(4); - __sdata = .; - *(.data .data.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __edata = .; - } > RAM AT > FLASH - - /* LMA of .data */ - __sidata = LOADADDR(.data); - - /* ### .bss */ - .bss : ALIGN(4) - { - . = ALIGN(4); - __sbss = .; - *(.bss .bss.*); - . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ - __ebss = .; - } > RAM - - /* ### .uninit */ - .uninit (NOLOAD) : ALIGN(4) - { - . = ALIGN(4); - *(.uninit .uninit.*); - . = ALIGN(4); - } > RAM - - /* Place the heap right after `.uninit` */ - . = ALIGN(4); - __sheap = .; - - /* ## .got */ - /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in - the input files and raise an error if relocatable code is found */ - .got (NOLOAD) : - { - KEEP(*(.got .got.*)); - } - - /* ## Discarded sections */ - /DISCARD/ : - { - /* Unused exception related info that only wastes space */ - *(.ARM.exidx); - *(.ARM.exidx.*); - *(.ARM.extab.*); - } -} - -/* Do not exceed this mark in the error messages below | */ -/* # Alignment checks */ -ASSERT(ORIGIN(FLASH) % 4 == 0, " -ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); - -ASSERT(ORIGIN(RAM) % 4 == 0, " -ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); - -ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " -BUG(cortex-m-rt): .data is not 4-byte aligned"); - -ASSERT(__sidata % 4 == 0, " -BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); - -ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " -BUG(cortex-m-rt): .bss is not 4-byte aligned"); - -ASSERT(__sheap % 4 == 0, " -BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); - -/* # Position checks */ - -/* ## .text */ -ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " -ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. -Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); - -/* # Other checks */ -ASSERT(SIZEOF(.got) == 0, " -ERROR(cortex-m-rt): .got section detected in the input object files -Dynamic relocations are not supported. If you are linking to C code compiled using -the 'cc' crate then modify your build script to compile the C code _without_ -the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); -/* Do not exceed this mark in the error messages above | */ diff --git a/neotron-os/neotron-flash-0002.ld b/neotron-os/neotron-os-arm.ld similarity index 96% rename from neotron-os/neotron-flash-0002.ld rename to neotron-os/neotron-os-arm.ld index 59626d9..9f31cbe 100644 --- a/neotron-os/neotron-flash-0002.ld +++ b/neotron-os/neotron-os-arm.ld @@ -21,8 +21,8 @@ /* Provides information about the memory layout of the device */ MEMORY { - /* The first 128 KiB is for the BIOS. We get the rest. */ - FLASH (rx) : ORIGIN = 0x00020000, LENGTH = 256K + /* The BIOS is before the OS, we get the rest. We place a large upper bound on the length. */ + FLASH (rx) : ORIGIN = ${{start_address}}, LENGTH = 4096K /* * We get the bottom 4KB of RAM. Anything above that is for applications * (up to wherever the BIOS tells us we can use.) diff --git a/neotron-os/src/bin/flash0002.rs b/neotron-os/src/bin/flash0002.rs deleted file mode 100644 index 8de5d7b..0000000 --- a/neotron-os/src/bin/flash0002.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Binary Neotron OS Image -//! -//! This is for Flash Addresses that start at `0x0002_0000`. -//! -//! Copyright (c) The Neotron Developers, 2022 -//! -//! Licence: GPL v3 or higher (see ../LICENCE.md) - -#![no_std] -#![no_main] - -/// This tells the BIOS how to start the OS. This must be the first four bytes -/// of our portion of Flash. -#[link_section = ".entry_point"] -#[used] -pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main; - -// End of file diff --git a/neotron-os/src/bin/flash0802.rs b/neotron-os/src/bin/flash0802.rs deleted file mode 100644 index 3e3a09e..0000000 --- a/neotron-os/src/bin/flash0802.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Binary Neotron OS Image -//! -//! This is for Flash Addresses that start at `0x0802_0000`. -//! -//! Copyright (c) The Neotron Developers, 2022 -//! -//! Licence: GPL v3 or higher (see ../LICENCE.md) - -#![no_std] -#![no_main] - -/// This tells the BIOS how to start the OS. This must be the first four bytes -/// of our portion of Flash. -#[link_section = ".entry_point"] -#[used] -pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main; - -// End of file diff --git a/neotron-os/src/bin/flash1002.rs b/neotron-os/src/main.rs similarity index 100% rename from neotron-os/src/bin/flash1002.rs rename to neotron-os/src/main.rs diff --git a/neotron-os/src/refcell.rs b/neotron-os/src/refcell.rs index fd85cf1..af7d630 100644 --- a/neotron-os/src/refcell.rs +++ b/neotron-os/src/refcell.rs @@ -92,7 +92,7 @@ pub struct CsRefCellGuard<'a, T> { parent: &'a CsRefCell, } -impl<'a, T> Deref for CsRefCellGuard<'a, T> { +impl Deref for CsRefCellGuard<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { @@ -101,14 +101,14 @@ impl<'a, T> Deref for CsRefCellGuard<'a, T> { } } -impl<'a, T> DerefMut for CsRefCellGuard<'a, T> { +impl DerefMut for CsRefCellGuard<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { let ptr = self.parent.inner.get(); unsafe { &mut *ptr } } } -impl<'a, T> Drop for CsRefCellGuard<'a, T> { +impl Drop for CsRefCellGuard<'_, T> { fn drop(&mut self) { // We hold this refcell guard exclusively, so this can't race self.parent.locked.store(false, Ordering::Release);