From ca7583e41905e03a148ebc8bad07561c0e1455c4 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Mon, 22 Jul 2024 17:01:25 +0100 Subject: [PATCH 1/4] Rename demo-app to nrf52-app --- .github/workflows/build-ferrocene.yml | 12 +++---- .github/workflows/build.yml | 12 +++---- .github/workflows/clippy.yml | 4 +-- .github/workflows/format.yml | 4 +-- build.sh | 2 +- {demo-app => nrf52-app}/.cargo/config.toml | 0 {demo-app => nrf52-app}/.gitignore | 0 {demo-app => nrf52-app}/.vscode/launch.json | 4 +-- {demo-app => nrf52-app}/.vscode/settings.json | 0 {demo-app => nrf52-app}/.vscode/tasks.json | 0 {demo-app => nrf52-app}/Cargo.lock | 34 +++++++++---------- {demo-app => nrf52-app}/Cargo.lock.license | 0 {demo-app => nrf52-app}/Cargo.toml | 2 +- {demo-app => nrf52-app}/README.md | 32 ++++++++--------- {demo-app => nrf52-app}/build.rs | 0 {demo-app => nrf52-app}/memory.x | 0 {demo-app => nrf52-app}/src/main.rs | 0 {demo-app => nrf52-app}/src/tx_low_level.S | 0 18 files changed, 53 insertions(+), 53 deletions(-) rename {demo-app => nrf52-app}/.cargo/config.toml (100%) rename {demo-app => nrf52-app}/.gitignore (100%) rename {demo-app => nrf52-app}/.vscode/launch.json (86%) rename {demo-app => nrf52-app}/.vscode/settings.json (100%) rename {demo-app => nrf52-app}/.vscode/tasks.json (100%) rename {demo-app => nrf52-app}/Cargo.lock (99%) rename {demo-app => nrf52-app}/Cargo.lock.license (100%) rename {demo-app => nrf52-app}/Cargo.toml (98%) rename {demo-app => nrf52-app}/README.md (62%) rename {demo-app => nrf52-app}/build.rs (100%) rename {demo-app => nrf52-app}/memory.x (100%) rename {demo-app => nrf52-app}/src/main.rs (100%) rename {demo-app => nrf52-app}/src/tx_low_level.S (100%) diff --git a/.github/workflows/build-ferrocene.yml b/.github/workflows/build-ferrocene.yml index 042c81c..84f50ce 100644 --- a/.github/workflows/build-ferrocene.yml +++ b/.github/workflows/build-ferrocene.yml @@ -5,7 +5,7 @@ name: workflow-build-everything-ferrocene run-name: Build Everything with Ferrocene on: [push] jobs: - job-build-demo-app: + job-build-nrf52-app: runs-on: ubuntu-latest steps: - name: Install Arm C compiler @@ -29,21 +29,21 @@ jobs: echo "BUILD_SLUG=${slug}" >> "${GITHUB_ENV}" - name: Check Demo App run: | - cd demo-app + cd nrf52-app rustc --version cargo --version cargo check --target=thumbv7em-none-eabi - name: Build Demo App run: | - cd demo-app + cd nrf52-app rustc --version cargo --version cargo build --target=thumbv7em-none-eabi --release - - name: Upload demo-app + - name: Upload nrf52-app uses: actions/upload-artifact@master with: - name: demo-app - path: demo-app/target/thumbv7em-none-eabi/release/demo-app + name: nrf52-app + path: nrf52-app/target/thumbv7em-none-eabi/release/nrf52-app job-build-threadx-sys: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c393662..be89626 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,7 +5,7 @@ name: workflow-build-everything run-name: Build Everything on: [push] jobs: - job-build-demo-app: + job-build-nrf52-app: runs-on: ubuntu-latest steps: - name: Install Arm C compiler @@ -29,17 +29,17 @@ jobs: echo "BUILD_SLUG=${slug}" >> "${GITHUB_ENV}" - name: Check Demo App run: | - cd demo-app + cd nrf52-app cargo check --target=thumbv7em-none-eabi - name: Build Demo App run: | - cd demo-app + cd nrf52-app cargo build --target=thumbv7em-none-eabi --release - - name: Upload demo-app + - name: Upload nrf52-app uses: actions/upload-artifact@master with: - name: demo-app - path: demo-app/target/thumbv7em-none-eabi/release/demo-app + name: nrf52-app + path: nrf52-app/target/thumbv7em-none-eabi/release/nrf52-app job-build-threadx-sys: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 0001b48..79f2290 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -5,7 +5,7 @@ name: workflow-code-analysis run-name: Run code analysis on: [push] jobs: - job-clippy-demo-app: + job-clippy-nrf52-app: runs-on: ubuntu-latest steps: - name: Checkout repo @@ -22,7 +22,7 @@ jobs: env: RUSTFLAGS: "-Dwarnings" run: | - cd demo-app + cd nrf52-app cargo clippy --all-features job-clippy-threadx-sys: runs-on: ubuntu-latest diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index e59a9ae..8a3eca1 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -5,14 +5,14 @@ name: workflow-code-format run-name: Check code formatting on: [push] jobs: - job-format-demo-app: + job-format-nrf52-app: runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Check Formatting run: | - cd demo-app + cd nrf52-app cargo fmt -- --check job-format-threadx-sys: runs-on: ubuntu-latest diff --git a/build.sh b/build.sh index f318018..da8e6ed 100755 --- a/build.sh +++ b/build.sh @@ -7,6 +7,6 @@ set -euo pipefail -pushd demo-app +pushd nrf52-app cargo build --release popd diff --git a/demo-app/.cargo/config.toml b/nrf52-app/.cargo/config.toml similarity index 100% rename from demo-app/.cargo/config.toml rename to nrf52-app/.cargo/config.toml diff --git a/demo-app/.gitignore b/nrf52-app/.gitignore similarity index 100% rename from demo-app/.gitignore rename to nrf52-app/.gitignore diff --git a/demo-app/.vscode/launch.json b/nrf52-app/.vscode/launch.json similarity index 86% rename from demo-app/.vscode/launch.json rename to nrf52-app/.vscode/launch.json index 6069033..3d63bd5 100644 --- a/demo-app/.vscode/launch.json +++ b/nrf52-app/.vscode/launch.json @@ -2,12 +2,12 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 { - // Use `nc localhost 8765 | defmt-print -e ./target/thumbv7em-none-eabihf/release/demo-app` to print the defmt output + // Use `nc localhost 8765 | defmt-print -e ./target/thumbv7em-none-eabihf/release/nrf52-app` to print the defmt output "version": "0.2.0", "configurations": [ { "cwd": "${workspaceRoot}", - "executable": "./target/thumbv7em-none-eabihf/release/demo-app", + "executable": "./target/thumbv7em-none-eabihf/release/nrf52-app", "name": "Debug Microcontroller (launch)", "request": "launch", "preLaunchTask": "rust: cargo build release", diff --git a/demo-app/.vscode/settings.json b/nrf52-app/.vscode/settings.json similarity index 100% rename from demo-app/.vscode/settings.json rename to nrf52-app/.vscode/settings.json diff --git a/demo-app/.vscode/tasks.json b/nrf52-app/.vscode/tasks.json similarity index 100% rename from demo-app/.vscode/tasks.json rename to nrf52-app/.vscode/tasks.json diff --git a/demo-app/Cargo.lock b/nrf52-app/Cargo.lock similarity index 99% rename from demo-app/Cargo.lock rename to nrf52-app/Cargo.lock index 377657f..ecf514d 100644 --- a/demo-app/Cargo.lock +++ b/nrf52-app/Cargo.lock @@ -242,23 +242,6 @@ dependencies = [ "defmt", ] -[[package]] -name = "demo-app" -version = "0.0.0" -dependencies = [ - "byte-strings", - "cc", - "cortex-m", - "cortex-m-rt", - "defmt", - "defmt-rtt", - "heapless", - "nrf52840-hal", - "panic-probe", - "static_cell", - "threadx-sys", -] - [[package]] name = "either" version = "1.9.0" @@ -478,6 +461,23 @@ dependencies = [ "vcell", ] +[[package]] +name = "nrf52-app" +version = "0.0.0" +dependencies = [ + "byte-strings", + "cc", + "cortex-m", + "cortex-m-rt", + "defmt", + "defmt-rtt", + "heapless", + "nrf52840-hal", + "panic-probe", + "static_cell", + "threadx-sys", +] + [[package]] name = "nrf52840-hal" version = "0.16.0" diff --git a/demo-app/Cargo.lock.license b/nrf52-app/Cargo.lock.license similarity index 100% rename from demo-app/Cargo.lock.license rename to nrf52-app/Cargo.lock.license diff --git a/demo-app/Cargo.toml b/nrf52-app/Cargo.toml similarity index 98% rename from demo-app/Cargo.toml rename to nrf52-app/Cargo.toml index 9ec263b..458d73a 100644 --- a/demo-app/Cargo.toml +++ b/nrf52-app/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Jonathan Pallant "] edition = "2021" license = "MIT OR Apache-2.0" -name = "demo-app" +name = "nrf52-app" version = "0.0.0" description = "Rust ThreadX demo on nRF52840" diff --git a/demo-app/README.md b/nrf52-app/README.md similarity index 62% rename from demo-app/README.md rename to nrf52-app/README.md index f522211..eaa806e 100644 --- a/demo-app/README.md +++ b/nrf52-app/README.md @@ -8,39 +8,39 @@ automatically. You will also need `probe-rs` from . ```console $ cargo run --release - Compiling demo-app v0.0.0 (/Users/jonathan/Documents/ferrous-systems/threadx-experiments/demo-app) + Compiling nrf52-app v0.0.0 (/Users/jonathan/Documents/ferrous-systems/threadx-experiments/nrf52-app) Finished `dev` profile [optimized + debuginfo] target(s) in 4.81s - Running `probe-rs run --chip nRF52840_xxAA target/thumbv7em-none-eabi/debug/demo-app` + Running `probe-rs run --chip nRF52840_xxAA target/thumbv7em-none-eabi/debug/nrf52-app` Erasing ✔ [00:00:00] [####################################] 12.00 KiB/12.00 KiB @ 33.03 KiB/s (eta 0s ) Programming ✔ [00:00:00] [####################################] 12.00 KiB/12.00 KiB @ 42.84 KiB/s (eta 0s ) Finished in 0.661s Hello, this is version unknown! -└─ demo_app::__cortex_m_rt_main @ src/main.rs:151 +└─ nrf52_app::__cortex_m_rt_main @ src/main.rs:151 Entering ThreadX kernel... -└─ demo_app::__cortex_m_rt_main @ src/main.rs:186 +└─ nrf52_app::__cortex_m_rt_main @ src/main.rs:186 In tx_application_define()... -└─ demo_app::tx_application_define @ src/main.rs:26 +└─ nrf52_app::tx_application_define @ src/main.rs:26 Stack allocated @ 0x20037444 -└─ demo_app::tx_application_define @ src/main.rs:59 +└─ nrf52_app::tx_application_define @ src/main.rs:59 Thread spawned (entry=12345678) @ 0x2003f440 -└─ demo_app::tx_application_define @ src/main.rs:85 +└─ nrf52_app::tx_application_define @ src/main.rs:85 Stack allocated @ 0x2003944c -└─ demo_app::tx_application_define @ src/main.rs:102 +└─ nrf52_app::tx_application_define @ src/main.rs:102 Thread spawned (entry=aabbccdd) @ 0x2003f4f8 -└─ demo_app::tx_application_define @ src/main.rs:128 +└─ nrf52_app::tx_application_define @ src/main.rs:128 I am my_thread(12345678) -└─ demo_app::my_thread @ src/main.rs:136 +└─ nrf52_app::my_thread @ src/main.rs:136 I am my_thread(aabbccdd) -└─ demo_app::my_thread @ src/main.rs:136 +└─ nrf52_app::my_thread @ src/main.rs:136 I am my_thread(12345678), count = 1 -└─ demo_app::my_thread @ src/main.rs:145 +└─ nrf52_app::my_thread @ src/main.rs:145 I am my_thread(aabbccdd), count = 1 -└─ demo_app::my_thread @ src/main.rs:145 +└─ nrf52_app::my_thread @ src/main.rs:145 I am my_thread(12345678), count = 2 -└─ demo_app::my_thread @ src/main.rs:145 +└─ nrf52_app::my_thread @ src/main.rs:145 I am my_thread(aabbccdd), count = 2 -└─ demo_app::my_thread @ src/main.rs:145 +└─ nrf52_app::my_thread @ src/main.rs:145 I am my_thread(12345678), count = 3 -└─ demo_app::my_thread @ src/main.rs:145 +└─ nrf52_app::my_thread @ src/main.rs:145 ... ``` diff --git a/demo-app/build.rs b/nrf52-app/build.rs similarity index 100% rename from demo-app/build.rs rename to nrf52-app/build.rs diff --git a/demo-app/memory.x b/nrf52-app/memory.x similarity index 100% rename from demo-app/memory.x rename to nrf52-app/memory.x diff --git a/demo-app/src/main.rs b/nrf52-app/src/main.rs similarity index 100% rename from demo-app/src/main.rs rename to nrf52-app/src/main.rs diff --git a/demo-app/src/tx_low_level.S b/nrf52-app/src/tx_low_level.S similarity index 100% rename from demo-app/src/tx_low_level.S rename to nrf52-app/src/tx_low_level.S From 67683c1ce83a37f6b8e7ac7a435fb5a9249133b3 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Mon, 22 Jul 2024 18:00:06 +0100 Subject: [PATCH 2/4] Add Cortex-R5 on ThreadX demo. Currently there's no timer interrupt, so the tasks hang. But it does boot. --- .github/workflows/build-ferrocene.yml | 43 +- .github/workflows/build.yml | 35 +- .github/workflows/clippy.yml | 21 +- .github/workflows/format.yml | 11 +- build.sh | 4 + criticalup.toml | 1 + qemu-cortex-r5-app/.cargo/config.toml | 9 + qemu-cortex-r5-app/.gitignore | 1 + qemu-cortex-r5-app/.vscode/settings.json | 3 + qemu-cortex-r5-app/Cargo.lock | 441 ++++++++++++++++++ qemu-cortex-r5-app/Cargo.toml | 20 + qemu-cortex-r5-app/build.rs | 243 ++++++++++ qemu-cortex-r5-app/commands.gdb | 3 + qemu-cortex-r5-app/linker.ld | 30 ++ qemu-cortex-r5-app/src/critical_section.rs | 34 ++ qemu-cortex-r5-app/src/lib.rs | 64 +++ qemu-cortex-r5-app/src/main.rs | 228 +++++++++ .../src/tx_initialize_low_level.S | 346 ++++++++++++++ qemu-cortex-r5-app/src/virt_uart.rs | 75 +++ 19 files changed, 1606 insertions(+), 6 deletions(-) create mode 100644 qemu-cortex-r5-app/.cargo/config.toml create mode 100644 qemu-cortex-r5-app/.gitignore create mode 100644 qemu-cortex-r5-app/.vscode/settings.json create mode 100644 qemu-cortex-r5-app/Cargo.lock create mode 100644 qemu-cortex-r5-app/Cargo.toml create mode 100644 qemu-cortex-r5-app/build.rs create mode 100644 qemu-cortex-r5-app/commands.gdb create mode 100644 qemu-cortex-r5-app/linker.ld create mode 100644 qemu-cortex-r5-app/src/critical_section.rs create mode 100644 qemu-cortex-r5-app/src/lib.rs create mode 100644 qemu-cortex-r5-app/src/main.rs create mode 100644 qemu-cortex-r5-app/src/tx_initialize_low_level.S create mode 100644 qemu-cortex-r5-app/src/virt_uart.rs diff --git a/.github/workflows/build-ferrocene.yml b/.github/workflows/build-ferrocene.yml index 84f50ce..b0a6fae 100644 --- a/.github/workflows/build-ferrocene.yml +++ b/.github/workflows/build-ferrocene.yml @@ -27,13 +27,13 @@ jobs: slug=$(./describe.sh "${GITHUB_REF}") echo "Building with slug '${slug}'" echo "BUILD_SLUG=${slug}" >> "${GITHUB_ENV}" - - name: Check Demo App + - name: Check nRF52 App run: | cd nrf52-app rustc --version cargo --version cargo check --target=thumbv7em-none-eabi - - name: Build Demo App + - name: Build nRF52 App run: | cd nrf52-app rustc --version @@ -44,6 +44,45 @@ jobs: with: name: nrf52-app path: nrf52-app/target/thumbv7em-none-eabi/release/nrf52-app + job-build-qemu-cortex-r5-app: + runs-on: ubuntu-latest + steps: + - name: Install Arm C compiler + run: | + sudo apt-get update -y && sudo apt-get -y install gcc-arm-none-eabi + curl --proto '=https' --tlsv1.2 -LsSf https://github.com/ferrocene/criticalup/releases/download/v1.0.1/criticalup-installer.sh | sh + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Install Ferrocene + env: + CRITICALUP_TOKEN: ${{ secrets.CRITICALUP_TOKEN }} + run: | + criticalup install + echo "$HOME/.local/share/criticalup/bin" >> $GITHUB_PATH + - name: Find slug name + run: | + slug=$(./describe.sh "${GITHUB_REF}") + echo "Building with slug '${slug}'" + echo "BUILD_SLUG=${slug}" >> "${GITHUB_ENV}" + - name: Check QEMU Cortex-R5 App + run: | + cd qemu-cortex-r5-app + rustc --version + cargo --version + cargo check --target=armv7r-none-eabihf + - name: Build QEMU Cortex-R5 App + run: | + cd qemu-cortex-r5-app + rustc --version + cargo --version + cargo build --target=armv7r-none-eabihf --release + - name: Upload QEMU Cortex-R5 App + uses: actions/upload-artifact@master + with: + name: qemu-cortex-r5-app + path: qemu-cortex-r5-app/target/armv7r-none-eabihf/release/qemu-cortex-r5-app job-build-threadx-sys: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index be89626..233c5d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,11 +27,11 @@ jobs: slug=$(./describe.sh "${GITHUB_REF}") echo "Building with slug '${slug}'" echo "BUILD_SLUG=${slug}" >> "${GITHUB_ENV}" - - name: Check Demo App + - name: Check nRF52 App run: | cd nrf52-app cargo check --target=thumbv7em-none-eabi - - name: Build Demo App + - name: Build nRF52 App run: | cd nrf52-app cargo build --target=thumbv7em-none-eabi --release @@ -40,6 +40,37 @@ jobs: with: name: nrf52-app path: nrf52-app/target/thumbv7em-none-eabi/release/nrf52-app + job-build-qemu-cortex-r5-app: + runs-on: ubuntu-latest + steps: + - name: Install Arm C compiler + run: | + sudo apt-get update -y && sudo apt-get -y install gcc-arm-none-eabi + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Add rustup target + run: | + rustup target add armv7r-none-eabihf + - name: Find slug name + run: | + slug=$(./describe.sh "${GITHUB_REF}") + echo "Building with slug '${slug}'" + echo "BUILD_SLUG=${slug}" >> "${GITHUB_ENV}" + - name: Check QEMU Cortex-R5 App + run: | + cd qemu-cortex-r5-app + cargo check --target=armv7r-none-eabihf + - name: Build QEMU Cortex-R5 App + run: | + cd qemu-cortex-r5-app + cargo build --target=armv7r-none-eabihf --release + - name: Upload qemu-cortex-r5-app + uses: actions/upload-artifact@master + with: + name: qemu-cortex-r5-app + path: qemu-cortex-r5-app/target/armv7r-none-eabihf/release/qemu-cortex-r5-app job-build-threadx-sys: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 79f2290..c772bdd 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -18,12 +18,31 @@ jobs: - name: Add rustup target run: | rustup target add thumbv7em-none-eabi - - name: Check Clippy on Demo App + - name: Check Clippy on nRF52 App env: RUSTFLAGS: "-Dwarnings" run: | cd nrf52-app cargo clippy --all-features + job-clippy-qemu-cortex-r5-app: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Install tools + run: | + sudo apt-get update -y && sudo apt-get -y install gcc-arm-none-eabi + - name: Add rustup target + run: | + rustup target add armv7r-none-eabihf + - name: Check Clippy on QEMU Cortex-R5 App + env: + RUSTFLAGS: "-Dwarnings" + run: | + cd qemu-cortex-r5-app + cargo clippy --all-features job-clippy-threadx-sys: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 8a3eca1..fe24ea9 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -10,10 +10,19 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v4 - - name: Check Formatting + - name: Check Formatting on nRF52 App run: | cd nrf52-app cargo fmt -- --check + job-format-qemu-cortex-r5-app: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Check Formatting on QEMU Cortex-R5 App + run: | + cd qemu-cortex-r5-app + cargo fmt -- --check job-format-threadx-sys: runs-on: ubuntu-latest steps: diff --git a/build.sh b/build.sh index da8e6ed..d7ee109 100755 --- a/build.sh +++ b/build.sh @@ -10,3 +10,7 @@ set -euo pipefail pushd nrf52-app cargo build --release popd + +pushd qemu-cortex-r5-app +cargo build --release +popd diff --git a/criticalup.toml b/criticalup.toml index e468a73..79c8c62 100644 --- a/criticalup.toml +++ b/criticalup.toml @@ -16,4 +16,5 @@ packages = [ "flip-link-${rustc-host}", "llvm-tools-${rustc-host}", "rust-std-thumbv7em-none-eabi", + "rust-std-armv7r-none-eabihf", ] diff --git a/qemu-cortex-r5-app/.cargo/config.toml b/qemu-cortex-r5-app/.cargo/config.toml new file mode 100644 index 0000000..fa7148c --- /dev/null +++ b/qemu-cortex-r5-app/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.armv7r-none-eabihf] +rustflags = [ + "-Clink-arg=-Tlinker.ld", + "-Ctarget-cpu=cortex-r5", +] +runner = "qemu-system-arm -machine versatileab -cpu cortex-r5f -semihosting -nographic -kernel" + +[build] +target = ["armv7r-none-eabihf"] diff --git a/qemu-cortex-r5-app/.gitignore b/qemu-cortex-r5-app/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/qemu-cortex-r5-app/.gitignore @@ -0,0 +1 @@ +/target diff --git a/qemu-cortex-r5-app/.vscode/settings.json b/qemu-cortex-r5-app/.vscode/settings.json new file mode 100644 index 0000000..7d7a538 --- /dev/null +++ b/qemu-cortex-r5-app/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.procMacro.enable": false +} diff --git a/qemu-cortex-r5-app/Cargo.lock b/qemu-cortex-r5-app/Cargo.lock new file mode 100644 index 0000000..165d69d --- /dev/null +++ b/qemu-cortex-r5-app/Cargo.lock @@ -0,0 +1,441 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "byte-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002ee5531feb8450e59862fefa550eeac39b726d60b186071672751045ebc29a" +dependencies = [ + "byte-strings-proc_macros", +] + +[[package]] +name = "byte-strings-proc_macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f7e0e71f98d6c71bfe42b0a7a47d0f870ad808401fad2d44fa156ed5b0ae03" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cc" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "embedded-alloc" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddae17915accbac2cfbc64ea0ae6e3b330e6ea124ba108dada63646fd3c6f815" +dependencies = [ + "critical-section", + "linked_list_allocator", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "portable-atomic" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qemu-cortex-r5-app" +version = "0.1.0" +dependencies = [ + "byte-strings", + "cc", + "critical-section", + "embedded-alloc", + "static_cell", + "threadx-sys", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "static_cell" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89b0684884a883431282db1e4343f34afc2ff6996fe1f4a1664519b66e14c1e" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "threadx-sys" +version = "0.1.0" +dependencies = [ + "bindgen", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +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/qemu-cortex-r5-app/Cargo.toml b/qemu-cortex-r5-app/Cargo.toml new file mode 100644 index 0000000..ff5183b --- /dev/null +++ b/qemu-cortex-r5-app/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "qemu-cortex-r5-app" +version = "0.1.0" +edition = "2021" +authors = ["Ferrous Systems"] +license = "MIT OR Apache-2.0" +description = "A simple ARMv7-R demo application that runs ThreadX in QEMU and compiles with Ferrocene" + +[dependencies] +critical-section = { version = "1.1.2", features = ["restore-state-bool"] } +embedded-alloc = "0.5.1" +static_cell = "2.1.0" +threadx-sys = { path = "../threadx-sys" } +byte-strings = "0.3.1" + +[profile.release] +opt-level = "s" + +[build-dependencies] +cc = "1.1.6" diff --git a/qemu-cortex-r5-app/build.rs b/qemu-cortex-r5-app/build.rs new file mode 100644 index 0000000..eeba1ed --- /dev/null +++ b/qemu-cortex-r5-app/build.rs @@ -0,0 +1,243 @@ +//! Build script for the Rust/ThreadX demo + +// SPDX-FileCopyrightText: Copyright (c) 2023 Ferrous Systems +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use std::{env, error::Error, fs, path::PathBuf}; + +static TX_PORT_FILES: &[&str] = &[ + "tx_thread_context_restore.S", + "tx_thread_fiq_nesting_end.S", + "tx_thread_interrupt_restore.S", + "tx_thread_stack_build.S", + "tx_thread_context_save.S", + "tx_thread_fiq_nesting_start.S", + "tx_thread_irq_nesting_end.S", + "tx_thread_system_return.S", + "tx_thread_fiq_context_restore.S", + "tx_thread_interrupt_control.S", + "tx_thread_irq_nesting_start.S", + "tx_thread_vectored_context_save.S", + "tx_thread_fiq_context_save.S", + "tx_thread_interrupt_disable.S", + "tx_thread_schedule.S", + "tx_timer_interrupt.S", +]; + +static TX_COMMON_FILES: &[&str] = &[ + "tx_block_allocate.c", + "tx_block_pool_cleanup.c", + "tx_block_pool_create.c", + "tx_block_pool_delete.c", + "tx_block_pool_info_get.c", + "tx_block_pool_initialize.c", + "tx_block_pool_performance_info_get.c", + "tx_block_pool_performance_system_info_get.c", + "tx_block_pool_prioritize.c", + "tx_block_release.c", + "tx_byte_allocate.c", + "tx_byte_pool_cleanup.c", + "tx_byte_pool_create.c", + "tx_byte_pool_delete.c", + "tx_byte_pool_info_get.c", + "tx_byte_pool_initialize.c", + "tx_byte_pool_performance_info_get.c", + "tx_byte_pool_performance_system_info_get.c", + "tx_byte_pool_prioritize.c", + "tx_byte_pool_search.c", + "tx_byte_release.c", + "tx_event_flags_cleanup.c", + "tx_event_flags_create.c", + "tx_event_flags_delete.c", + "tx_event_flags_get.c", + "tx_event_flags_info_get.c", + "tx_event_flags_initialize.c", + "tx_event_flags_performance_info_get.c", + "tx_event_flags_performance_system_info_get.c", + "tx_event_flags_set.c", + "tx_event_flags_set_notify.c", + "tx_initialize_high_level.c", + "tx_initialize_kernel_enter.c", + "tx_initialize_kernel_setup.c", + "tx_mutex_cleanup.c", + "tx_mutex_create.c", + "tx_mutex_delete.c", + "tx_mutex_get.c", + "tx_mutex_info_get.c", + "tx_mutex_initialize.c", + "tx_mutex_performance_info_get.c", + "tx_mutex_performance_system_info_get.c", + "tx_mutex_prioritize.c", + "tx_mutex_priority_change.c", + "tx_mutex_put.c", + "tx_queue_cleanup.c", + "tx_queue_create.c", + "tx_queue_delete.c", + "tx_queue_flush.c", + "tx_queue_front_send.c", + "tx_queue_info_get.c", + "tx_queue_initialize.c", + "tx_queue_performance_info_get.c", + "tx_queue_performance_system_info_get.c", + "tx_queue_prioritize.c", + "tx_queue_receive.c", + "tx_queue_send.c", + "tx_queue_send_notify.c", + "tx_semaphore_ceiling_put.c", + "tx_semaphore_cleanup.c", + "tx_semaphore_create.c", + "tx_semaphore_delete.c", + "tx_semaphore_get.c", + "tx_semaphore_info_get.c", + "tx_semaphore_initialize.c", + "tx_semaphore_performance_info_get.c", + "tx_semaphore_performance_system_info_get.c", + "tx_semaphore_prioritize.c", + "tx_semaphore_put.c", + "tx_semaphore_put_notify.c", + "tx_thread_create.c", + "tx_thread_delete.c", + "tx_thread_entry_exit_notify.c", + "tx_thread_identify.c", + "tx_thread_info_get.c", + "tx_thread_initialize.c", + "tx_thread_performance_info_get.c", + "tx_thread_performance_system_info_get.c", + "tx_thread_preemption_change.c", + "tx_thread_priority_change.c", + "tx_thread_relinquish.c", + "tx_thread_reset.c", + "tx_thread_resume.c", + "tx_thread_shell_entry.c", + "tx_thread_sleep.c", + "tx_thread_stack_analyze.c", + "tx_thread_stack_error_handler.c", + "tx_thread_stack_error_notify.c", + "tx_thread_suspend.c", + "tx_thread_system_preempt_check.c", + "tx_thread_system_resume.c", + "tx_thread_system_suspend.c", + "tx_thread_terminate.c", + "tx_thread_time_slice.c", + "tx_thread_time_slice_change.c", + "tx_thread_timeout.c", + "tx_thread_wait_abort.c", + "tx_time_get.c", + "tx_time_set.c", + "tx_timer_activate.c", + "tx_timer_change.c", + "tx_timer_create.c", + "tx_timer_deactivate.c", + "tx_timer_delete.c", + "tx_timer_expiration_process.c", + "tx_timer_info_get.c", + "tx_timer_initialize.c", + "tx_timer_performance_info_get.c", + "tx_timer_performance_system_info_get.c", + "tx_timer_system_activate.c", + "tx_timer_system_deactivate.c", + "tx_timer_thread_entry.c", + "tx_trace_buffer_full_notify.c", + "tx_trace_enable.c", + "tx_trace_event_filter.c", + "tx_trace_event_unfilter.c", + "tx_trace_disable.c", + "tx_trace_initialize.c", + "tx_trace_interrupt_control.c", + "tx_trace_isr_enter_insert.c", + "tx_trace_isr_exit_insert.c", + "tx_trace_object_register.c", + "tx_trace_object_unregister.c", + "tx_trace_user_event_insert.c", + "txe_block_allocate.c", + "txe_block_pool_create.c", + "txe_block_pool_delete.c", + "txe_block_pool_info_get.c", + "txe_block_pool_prioritize.c", + "txe_block_release.c", + "txe_byte_allocate.c", + "txe_byte_pool_create.c", + "txe_byte_pool_delete.c", + "txe_byte_pool_info_get.c", + "txe_byte_pool_prioritize.c", + "txe_byte_release.c", + "txe_event_flags_create.c", + "txe_event_flags_delete.c", + "txe_event_flags_get.c", + "txe_event_flags_info_get.c", + "txe_event_flags_set.c", + "txe_event_flags_set_notify.c", + "txe_mutex_create.c", + "txe_mutex_delete.c", + "txe_mutex_get.c", + "txe_mutex_info_get.c", + "txe_mutex_prioritize.c", + "txe_mutex_put.c", + "txe_queue_create.c", + "txe_queue_delete.c", + "txe_queue_flush.c", + "txe_queue_front_send.c", + "txe_queue_info_get.c", + "txe_queue_prioritize.c", + "txe_queue_receive.c", + "txe_queue_send.c", + "txe_queue_send_notify.c", + "txe_semaphore_ceiling_put.c", + "txe_semaphore_create.c", + "txe_semaphore_delete.c", + "txe_semaphore_get.c", + "txe_semaphore_info_get.c", + "txe_semaphore_prioritize.c", + "txe_semaphore_put.c", + "txe_semaphore_put_notify.c", + "txe_thread_create.c", + "txe_thread_delete.c", + "txe_thread_entry_exit_notify.c", + "txe_thread_info_get.c", + "txe_thread_preemption_change.c", + "txe_thread_priority_change.c", + "txe_thread_relinquish.c", + "txe_thread_reset.c", + "txe_thread_resume.c", + "txe_thread_suspend.c", + "txe_thread_terminate.c", + "txe_thread_time_slice_change.c", + "txe_thread_wait_abort.c", + "txe_timer_activate.c", + "txe_timer_change.c", + "txe_timer_create.c", + "txe_timer_deactivate.c", + "txe_timer_delete.c", + "txe_timer_info_get.c", +]; + +fn main() -> Result<(), Box> { + let out_dir = PathBuf::from(env::var("OUT_DIR")?); + let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + + // put memory layout (linker script) in the linker search path + fs::copy("linker.ld", out_dir.join("linker.ld"))?; + println!("cargo:rustc-link-search={}", out_dir.display()); + println!("cargo:rerun-if-changed=linker.ld"); + + // Build our ThreadX static library + let tx_common_dir = crate_dir.join("../threadx/common/src"); + let tx_common_inc = crate_dir.join("../threadx/common/inc"); + let tx_port_dir = crate_dir.join("../threadx/ports/cortex_r5/gnu/src"); + let tx_port_inc = crate_dir.join("../threadx/ports/cortex_r5/gnu/inc"); + cc::Build::new() + .include(&tx_common_inc) + .include(&tx_port_inc) + .define("TX_ENABLE_VFP_SUPPORT", "1") + .files(TX_PORT_FILES.iter().map(|&s| tx_port_dir.join(s))) + .files(TX_COMMON_FILES.iter().map(|&s| tx_common_dir.join(s))) + .compile("threadx"); + + cc::Build::new() + .include(&tx_common_inc) + .include(&tx_port_inc) + .file("src/tx_initialize_low_level.S") + .compile("startup"); + + Ok(()) +} diff --git a/qemu-cortex-r5-app/commands.gdb b/qemu-cortex-r5-app/commands.gdb new file mode 100644 index 0000000..bbfd2a5 --- /dev/null +++ b/qemu-cortex-r5-app/commands.gdb @@ -0,0 +1,3 @@ +target extended-remote :1234 +layout split + diff --git a/qemu-cortex-r5-app/linker.ld b/qemu-cortex-r5-app/linker.ld new file mode 100644 index 0000000..cf182ab --- /dev/null +++ b/qemu-cortex-r5-app/linker.ld @@ -0,0 +1,30 @@ +MEMORY { + RAM : ORIGIN = 0, LENGTH = 0x1000000 +} + +ENTRY(_start) +SECTIONS { + .startup ORIGIN(RAM) : { + *(.text.startup) + } > RAM + .text : { *(.text .text*) } > RAM + .rodata : { *(.rodata .rodata*) } > RAM + .data : { *(.data .data*) } > RAM + .bss : { *(.bss .bss* COMMON) } > RAM + /DISCARD/ : { + *(.note .note*) + } + + . = ALIGN(16); + .stack : { + _stack_bottom = ABSOLUTE(.) ; + /* Allocate room for stack. This must be big enough for the IRQ, FIQ, and + SYS stack if nested interrupts are enabled. */ + . = ALIGN(8) ; + . += 0x10000; + _sp = . - 16 ; + _stack_top = ABSOLUTE(.) ; + } > RAM + + _end = .; __end__ = . ; +} diff --git a/qemu-cortex-r5-app/src/critical_section.rs b/qemu-cortex-r5-app/src/critical_section.rs new file mode 100644 index 0000000..2961d92 --- /dev/null +++ b/qemu-cortex-r5-app/src/critical_section.rs @@ -0,0 +1,34 @@ +//! Code that implements the `critical-section` traits on Cortex-R. + +struct SingleCoreCriticalSection; +critical_section::set_impl!(SingleCoreCriticalSection); + +/// Reads the CPU interrupt status bit from CPSR +/// +/// Returns true if interrupts enabled. +#[inline] +pub fn interrupts_enabled() -> bool { + const CPSR_I_BIT: u32 = 1 << 7; + let r: u32; + unsafe { + core::arch::asm!("mrs {}, CPSR", out(reg) r, options(nomem, nostack, preserves_flags)) + }; + r & CPSR_I_BIT != 0 +} + +unsafe impl critical_section::Impl for SingleCoreCriticalSection { + unsafe fn acquire() -> critical_section::RawRestoreState { + let was_active = interrupts_enabled(); + core::arch::asm!("cpsid i", options(nomem, nostack, preserves_flags)); + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); + was_active + } + + unsafe fn release(was_active: critical_section::RawRestoreState) { + // Only re-enable interrupts if they were enabled before the critical section. + if was_active { + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); + core::arch::asm!("cpsie i", options(nomem, nostack, preserves_flags)); + } + } +} diff --git a/qemu-cortex-r5-app/src/lib.rs b/qemu-cortex-r5-app/src/lib.rs new file mode 100644 index 0000000..8f48406 --- /dev/null +++ b/qemu-cortex-r5-app/src/lib.rs @@ -0,0 +1,64 @@ +#![no_std] + +pub mod critical_section; +pub mod virt_uart; + +core::arch::global_asm!( + r#" + +.section .text.startup +.global _start +.global _vectors +.code 32 +.align 0 +// Work around https://github.com/rust-lang/rust/issues/127269 +.fpu vfp3-d16 + +__vectors: + LDR pc, STARTUP @ Reset goes to startup function + LDR pc, UNDEFINED @ Undefined handler + LDR pc, SWI @ Software interrupt handler + LDR pc, PREFETCH @ Prefetch exception handler + LDR pc, ABORT @ Abort exception handler + LDR pc, RESERVED @ Reserved exception handler + LDR pc, IRQ @ IRQ interrupt handler + LDR pc, FIQ @ FIQ interrupt handler + +STARTUP: + .word _start @ Reset goes to C startup function +UNDEFINED: + .word __tx_undefined @ Undefined handler +SWI: + .word __tx_swi_interrupt @ Software interrupt handler +PREFETCH: + .word __tx_prefetch_handler @ Prefetch exception handler +ABORT: + .word __tx_abort_handler @ Abort exception handler +RESERVED: + .word __tx_reserved_handler @ Reserved exception handler +IRQ: + .word __tx_irq_handler @ IRQ interrupt handler +FIQ: + .word __tx_fiq_handler @ FIQ interrupt handler + +_start: + // Set stack pointer + ldr sp, =_stack_top + + // Allow VFP coprocessor access + mrc p15, 0, r0, c1, c0, 2 + orr r0, r0, #0xF00000 + mcr p15, 0, r0, c1, c0, 2 + + // Enable VFP + mov r0, #0x40000000 + vmsr fpexc, r0 + + // Jump to application + bl kmain + + // In case the application returns, loop forever + b . + +"# +); diff --git a/qemu-cortex-r5-app/src/main.rs b/qemu-cortex-r5-app/src/main.rs new file mode 100644 index 0000000..7887677 --- /dev/null +++ b/qemu-cortex-r5-app/src/main.rs @@ -0,0 +1,228 @@ +//! Rust Demo for a QEMU Cortex-R machine, running ThreadX + +// SPDX-FileCopyrightText: Copyright (c) 2023 Ferrous Systems +// SPDX-License-Identifier: MIT OR Apache-2.0 + +#![no_std] +#![no_main] + +use byte_strings::c; +use core::{cell::RefCell, fmt::Write}; +use critical_section::Mutex; +use qemu_cortex_r5_app::virt_uart::Uart; +use static_cell::StaticCell; + +static BUILD_SLUG: Option<&str> = option_env!("BUILD_SLUG"); + +const DEMO_STACK_SIZE: usize = 1024; + +static UART: GlobalUart = GlobalUart::new(); + +struct GlobalUart { + inner: Mutex>>>, +} + +impl GlobalUart { + /// Create a new, empty, global UART wrapper + const fn new() -> GlobalUart { + GlobalUart { + inner: Mutex::new(RefCell::new(None)), + } + } + + /// Store a new UART at run-time + /// + /// Gives you back the old one, if any. + fn store(&self, uart: Uart<0x101f_1000>) -> Option> { + critical_section::with(|cs| { + let mut uart_ref = self.inner.borrow_ref_mut(cs); + uart_ref.replace(uart) + }) + } +} + +// Note that we're implementing for `&GlobalUart`, so we can write to a shared +// reference instead of requiring an exclusive-mutable reference. +impl core::fmt::Write for &GlobalUart { + /// Write the string to the inner UART, with a lock held + fn write_str(&mut self, s: &str) -> core::fmt::Result { + critical_section::with(|cs| { + let mut maybe_uart = self.inner.borrow_ref_mut(cs); + let Some(uart) = maybe_uart.as_mut() else { + return Err(core::fmt::Error); + }; + uart.write_str(s) + }) + } +} + +#[no_mangle] +extern "C" fn tx_application_define(_first_unused_memory: *mut core::ffi::c_void) { + _ = writeln!(&UART, "In tx_application_define()..."); + + // ThreadX requires a non-const pointer to char for the names, which it + // wil hold on to in the object, so it must have static lifetime. So we + // cast-away-const on a static string slice to appease the API. + + let byte_pool = { + static BYTE_POOL: StaticCell = StaticCell::new(); + static BYTE_POOL_STORAGE: StaticCell<[u8; 32768]> = StaticCell::new(); + let byte_pool = BYTE_POOL.uninit(); + let byte_pool_storage = BYTE_POOL_STORAGE.uninit(); + unsafe { + threadx_sys::_tx_byte_pool_create( + byte_pool.as_mut_ptr(), + c!("byte-pool0").as_ptr() as *mut threadx_sys::CHAR, + byte_pool_storage.as_mut_ptr() as *mut _, + core::mem::size_of_val(&BYTE_POOL_STORAGE) as u32, + ); + byte_pool.assume_init_mut() + } + }; + + let entry = 0x12345678; + let thread0 = { + let mut stack_pointer = core::ptr::null_mut(); + unsafe { + threadx_sys::_tx_byte_allocate( + byte_pool, + &mut stack_pointer, + DEMO_STACK_SIZE as _, + threadx_sys::TX_NO_WAIT, + ); + } + _ = writeln!(&UART, "Stack allocated @ {:p}", stack_pointer); + if stack_pointer.is_null() { + panic!("No space for stack"); + } + + static THREAD_STORAGE: StaticCell = StaticCell::new(); + let thread = THREAD_STORAGE.uninit(); + unsafe { + let res = threadx_sys::_tx_thread_create( + thread.as_mut_ptr(), + c!("thread0").as_ptr() as *mut threadx_sys::CHAR, + Some(my_thread), + entry, + stack_pointer, + DEMO_STACK_SIZE as _, + 1, + 1, + threadx_sys::TX_NO_TIME_SLICE, + threadx_sys::TX_AUTO_START, + ); + if res != threadx_sys::TX_SUCCESS { + panic!("Failed to create thread: {}", res); + } + thread.assume_init_mut() + } + }; + _ = writeln!( + &UART, + "Thread spawned (entry={:08x}) @ {:p}", + entry, thread0 as *const _ + ); + + let entry = 0xAABBCCDD; + let thread1 = { + let mut stack_pointer = core::ptr::null_mut(); + unsafe { + threadx_sys::_tx_byte_allocate( + byte_pool, + &mut stack_pointer, + DEMO_STACK_SIZE as _, + threadx_sys::TX_NO_WAIT, + ); + } + _ = writeln!(&UART, "Stack allocated @ {:p}", stack_pointer); + if stack_pointer.is_null() { + panic!("No space for stack"); + } + + static THREAD_STORAGE: StaticCell = StaticCell::new(); + let thread = THREAD_STORAGE.uninit(); + unsafe { + let res = threadx_sys::_tx_thread_create( + thread.as_mut_ptr(), + c!("thread1").as_ptr() as *mut threadx_sys::CHAR, + Some(my_thread), + entry, + stack_pointer, + DEMO_STACK_SIZE as _, + 1, + 1, + threadx_sys::TX_NO_TIME_SLICE, + threadx_sys::TX_AUTO_START, + ); + if res != threadx_sys::TX_SUCCESS { + panic!("Failed to create thread: {}", res); + } + thread.assume_init_mut() + } + }; + _ = writeln!( + &UART, + "Thread spawned (entry={:08x}) @ {:p}", + entry, thread1 as *const _ + ); +} + +extern "C" fn my_thread(value: u32) { + _ = writeln!(&UART, "I am my_thread({:08x})", value); + let mut thread_counter = 0; + loop { + thread_counter += 1; + + unsafe { + threadx_sys::_tx_thread_sleep(100); + } + + _ = writeln!( + &UART, + "I am my_thread({:08x}), count = {}", + value, thread_counter + ); + } +} + +/// The entry-point to the Rust application. +/// +/// It is called by the start-up code in `lib.rs`. +#[no_mangle] +pub extern "C" fn kmain() { + let uart0 = unsafe { Uart::new_uart0() }; + UART.store(uart0); + _ = writeln!( + &UART, + "Hello, this is version {}!", + BUILD_SLUG.unwrap_or("unknown") + ); + _ = writeln!(&UART, "Entering ThreadX kernel..."); + unsafe { + threadx_sys::_tx_initialize_kernel_enter(); + } + + panic!("Kernel exited"); +} + +/// Called when the application raises an unrecoverable `panic!`. +/// +/// Prints the panic to the console and then exits QEMU using a semihosting +/// breakpoint. +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + const SYS_REPORTEXC: u32 = 0x18; + let _ = writeln!(&UART, "PANIC: {:?}", info); + loop { + // Exit, using semihosting + unsafe { + core::arch::asm!( + "svc 0x123456", + in("r0") SYS_REPORTEXC, + in("r1") 0x20026 + ) + } + } +} + +// End of file diff --git a/qemu-cortex-r5-app/src/tx_initialize_low_level.S b/qemu-cortex-r5-app/src/tx_initialize_low_level.S new file mode 100644 index 0000000..a347127 --- /dev/null +++ b/qemu-cortex-r5-app/src/tx_initialize_low_level.S @@ -0,0 +1,346 @@ +@/*************************************************************************** +@ * Copyright (c) 2024 Microsoft Corporation +@ * +@ * This program and the accompanying materials are made available under the +@ * terms of the MIT License which is available at +@ * https://opensource.org/licenses/MIT. +@ * +@ * SPDX-License-Identifier: MIT +@ **************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Initialize */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_initialize.h" +@#include "tx_thread.h" +@#include "tx_timer.h" + + .arm + +SVC_MODE = 0xD3 @ Disable IRQ/FIQ SVC mode +IRQ_MODE = 0xD2 @ Disable IRQ/FIQ IRQ mode +FIQ_MODE = 0xD1 @ Disable IRQ/FIQ FIQ mode +SYS_MODE = 0xDF @ Disable IRQ/FIQ SYS mode +FIQ_STACK_SIZE = 512 @ FIQ stack size +IRQ_STACK_SIZE = 1024 @ IRQ stack size +SYS_STACK_SIZE = 1024 @ System stack size +@ +@ + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory + .global _tx_thread_context_save + .global _tx_thread_context_restore + .global _tx_timer_interrupt + .global _end + .global _sp + .global _stack_bottom + +@ +@ +@/* Define the 16-bit Thumb mode veneer for _tx_initialize_low_level for +@ applications calling this function from to 16-bit Thumb mode. */ +@ + .text + .align 2 + .thumb + .global $_tx_initialize_low_level + .type $_tx_initialize_low_level,function +$_tx_initialize_low_level: + BX pc @ Switch to 32-bit mode + NOP @ + .arm + STMFD sp!, {lr} @ Save return address + BL _tx_initialize_low_level @ Call _tx_initialize_low_level function + LDMFD sp!, {lr} @ Recover saved return address + BX lr @ Return to 16-bit caller +@ +@ + .text + .align 2 +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_initialize_low_level Cortex-R5/GNU */ +@/* 6.1 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for any low-level processor */ +@/* initialization, including setting up interrupt vectors, setting */ +@/* up a periodic timer interrupt source, saving the system stack */ +@/* pointer for use in ISR processing later, and finding the first */ +@/* available RAM memory address for tx_application_define. */ +@/* */ +@/* INPUT */ +@/* */ +@/* None */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* None */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* _tx_initialize_kernel_enter ThreadX entry function */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_initialize_low_level(VOID) +@{ + .global _tx_initialize_low_level + .type _tx_initialize_low_level,function +_tx_initialize_low_level: +@ +@ /* We must be in SVC mode at this point! */ +@ +@ /* Setup various stack pointers. */ +@ + LDR r1, =_sp @ Get pointer to stack area + +#ifdef TX_ENABLE_IRQ_NESTING +@ +@ /* Setup the system mode stack for nested interrupt support */ +@ + LDR r2, =SYS_STACK_SIZE @ Pickup stack size + MOV r3, #SYS_MODE @ Build SYS mode CPSR + MSR CPSR_c, r3 @ Enter SYS mode + SUB r1, r1, #1 @ Backup 1 byte + BIC r1, r1, #7 @ Ensure 8-byte alignment + MOV sp, r1 @ Setup SYS stack pointer + SUB r1, r1, r2 @ Calculate start of next stack +#endif + + LDR r2, =FIQ_STACK_SIZE @ Pickup stack size + MOV r0, #FIQ_MODE @ Build FIQ mode CPSR + MSR CPSR, r0 @ Enter FIQ mode + SUB r1, r1, #1 @ Backup 1 byte + BIC r1, r1, #7 @ Ensure 8-byte alignment + MOV sp, r1 @ Setup FIQ stack pointer + SUB r1, r1, r2 @ Calculate start of next stack + LDR r2, =IRQ_STACK_SIZE @ Pickup IRQ stack size + MOV r0, #IRQ_MODE @ Build IRQ mode CPSR + MSR CPSR, r0 @ Enter IRQ mode + SUB r1, r1, #1 @ Backup 1 byte + BIC r1, r1, #7 @ Ensure 8-byte alignment + MOV sp, r1 @ Setup IRQ stack pointer + SUB r3, r1, r2 @ Calculate end of IRQ stack + MOV r0, #SVC_MODE @ Build SVC mode CPSR + MSR CPSR, r0 @ Enter SVC mode + LDR r2, =_stack_bottom @ Pickup stack bottom + CMP r3, r2 @ Compare the current stack end with the bottom +_stack_error_loop: + BLT _stack_error_loop @ If the IRQ stack exceeds the stack bottom, just sit here! +@ +@ /* Save the system stack pointer. */ +@ _tx_thread_system_stack_ptr = (VOID_PTR) (sp); +@ + LDR r2, =_tx_thread_system_stack_ptr @ Pickup stack pointer + STR r1, [r2] @ Save the system stack +@ +@ /* Save the first available memory address. */ +@ _tx_initialize_unused_memory = (VOID_PTR) _end; +@ + LDR r1, =_end @ Get end of non-initialized RAM area + LDR r2, =_tx_initialize_unused_memory @ Pickup unused memory ptr address + ADD r1, r1, #8 @ Increment to next free word + STR r1, [r2] @ Save first free memory address +@ +@ /* Setup Timer for periodic interrupts. */ +@ +@ /* Done, return to caller. */ +@ +#ifdef __THUMB_INTERWORK + BX lr @ Return to caller +#else + MOV pc, lr @ Return to caller +#endif +@} +@ +@ +@/* Define shells for each of the interrupt vectors. */ +@ + .global __tx_undefined +__tx_undefined: + B __tx_undefined @ Undefined handler +@ + .global __tx_swi_interrupt +__tx_swi_interrupt: + B __tx_swi_interrupt @ Software interrupt handler +@ + .global __tx_prefetch_handler +__tx_prefetch_handler: + B __tx_prefetch_handler @ Prefetch exception handler +@ + .global __tx_abort_handler +__tx_abort_handler: + B __tx_abort_handler @ Abort exception handler +@ + .global __tx_reserved_handler +__tx_reserved_handler: + B __tx_reserved_handler @ Reserved exception handler +@ + .global __tx_irq_handler + .global __tx_irq_processing_return +__tx_irq_handler: +@ +@ /* Jump to context save to save system context. */ + B _tx_thread_context_save +__tx_irq_processing_return: +@ +@ /* At this point execution is still in the IRQ mode. The CPSR, point of +@ interrupt, and all C scratch registers are available for use. In +@ addition, IRQ interrupts may be re-enabled - with certain restrictions - +@ if nested IRQ interrupts are desired. Interrupts may be re-enabled over +@ small code sequences where lr is saved before enabling interrupts and +@ restored after interrupts are again disabled. */ +@ +@ /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start +@ from IRQ mode with interrupts disabled. This routine switches to the +@ system mode and returns with IRQ interrupts enabled. +@ +@ NOTE: It is very important to ensure all IRQ interrupts are cleared +@ prior to enabling nested IRQ interrupts. */ +#ifdef TX_ENABLE_IRQ_NESTING + BL _tx_thread_irq_nesting_start +#endif +@ +@ /* For debug purpose, execute the timer interrupt processing here. In +@ a real system, some kind of status indication would have to be checked +@ before the timer interrupt handler could be called. */ +@ + BL _tx_timer_interrupt @ Timer interrupt handler +@ +@ +@ /* If interrupt nesting was started earlier, the end of interrupt nesting +@ service must be called before returning to _tx_thread_context_restore. +@ This routine returns in processing in IRQ mode with interrupts disabled. */ +#ifdef TX_ENABLE_IRQ_NESTING + BL _tx_thread_irq_nesting_end +#endif +@ +@ /* Jump to context restore to restore system context. */ + B _tx_thread_context_restore +@ +@ +@ /* This is an example of a vectored IRQ handler. */ +@ +@ .global __tx_example_vectored_irq_handler +@__tx_example_vectored_irq_handler: +@ +@ +@ /* Save initial context and call context save to prepare for +@ vectored ISR execution. */ +@ +@ STMDB sp!, {r0-r3} @ Save some scratch registers +@ MRS r0, SPSR @ Pickup saved SPSR +@ SUB lr, lr, #4 @ Adjust point of interrupt +@ STMDB sp!, {r0, r10, r12, lr} @ Store other scratch registers +@ BL _tx_thread_vectored_context_save @ Vectored context save +@ +@ /* At this point execution is still in the IRQ mode. The CPSR, point of +@ interrupt, and all C scratch registers are available for use. In +@ addition, IRQ interrupts may be re-enabled - with certain restrictions - +@ if nested IRQ interrupts are desired. Interrupts may be re-enabled over +@ small code sequences where lr is saved before enabling interrupts and +@ restored after interrupts are again disabled. */ +@ +@ +@ /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start +@ from IRQ mode with interrupts disabled. This routine switches to the +@ system mode and returns with IRQ interrupts enabled. +@ +@ NOTE: It is very important to ensure all IRQ interrupts are cleared +@ prior to enabling nested IRQ interrupts. */ +@#ifdef TX_ENABLE_IRQ_NESTING +@ BL _tx_thread_irq_nesting_start +@#endif +@ +@ /* Application IRQ handlers can be called here! */ +@ +@ /* If interrupt nesting was started earlier, the end of interrupt nesting +@ service must be called before returning to _tx_thread_context_restore. +@ This routine returns in processing in IRQ mode with interrupts disabled. */ +@#ifdef TX_ENABLE_IRQ_NESTING +@ BL _tx_thread_irq_nesting_end +@#endif +@ +@ /* Jump to context restore to restore system context. */ +@ B _tx_thread_context_restore +@ +@ +#ifdef TX_ENABLE_FIQ_SUPPORT + .global __tx_fiq_handler + .global __tx_fiq_processing_return +__tx_fiq_handler: +@ +@ /* Jump to fiq context save to save system context. */ + B _tx_thread_fiq_context_save +__tx_fiq_processing_return: +@ +@ /* At this point execution is still in the FIQ mode. The CPSR, point of +@ interrupt, and all C scratch registers are available for use. */ +@ +@ /* Interrupt nesting is allowed after calling _tx_thread_fiq_nesting_start +@ from FIQ mode with interrupts disabled. This routine switches to the +@ system mode and returns with FIQ interrupts enabled. +@ +@ NOTE: It is very important to ensure all FIQ interrupts are cleared +@ prior to enabling nested FIQ interrupts. */ +#ifdef TX_ENABLE_FIQ_NESTING + BL _tx_thread_fiq_nesting_start +#endif +@ +@ /* Application FIQ handlers can be called here! */ +@ +@ /* If interrupt nesting was started earlier, the end of interrupt nesting +@ service must be called before returning to _tx_thread_fiq_context_restore. */ +#ifdef TX_ENABLE_FIQ_NESTING + BL _tx_thread_fiq_nesting_end +#endif +@ +@ /* Jump to fiq context restore to restore system context. */ + B _tx_thread_fiq_context_restore +@ +@ +#else + .global __tx_fiq_handler +__tx_fiq_handler: + B __tx_fiq_handler @ FIQ interrupt handler +#endif +@ +@ +BUILD_OPTIONS: + .word _tx_build_options @ Reference to bring in +VERSION_ID: + .word _tx_version_id @ Reference to bring in + + + diff --git a/qemu-cortex-r5-app/src/virt_uart.rs b/qemu-cortex-r5-app/src/virt_uart.rs new file mode 100644 index 0000000..fab913b --- /dev/null +++ b/qemu-cortex-r5-app/src/virt_uart.rs @@ -0,0 +1,75 @@ +//! A driver the Arm PL011 Uart +//! +//! Written by Jonathan Pallant at Ferrous Systems +//! +//! Copyright (c) Ferrous Systems, 2024 + +/// A driver for a virtual PL011 Uart +/// +/// It skips almost all the important initialisation, but it works on QEMU. +pub struct Uart(); + +impl Uart<0x101f_1000> { + /// Create a new UART object for UART0 + /// + /// # Safety + /// + /// Only construct one object per UART at any given time. + pub unsafe fn new_uart0() -> Self { + let mut u = Uart(); + u.set_control(Self::CONTROL_UARTEN | Self::CONTROL_TXE); + u + } +} + +impl Uart { + const FLAG_TXFF: u32 = 1 << 5; + const CONTROL_UARTEN: u32 = 1 << 0; + const CONTROL_TXE: u32 = 1 << 8; + + const DATA_OFFSET: usize = 0x000 >> 2; + const FLAG_OFFSET: usize = 0x018 >> 2; + const CONTROL_OFFSET: usize = 0x030 >> 2; + + /// Write a byte (blocking if there's no space) + pub fn write(&mut self, byte: u8) { + // Check the TX FIFO Full bit + while (self.get_flags() & Self::FLAG_TXFF) != 0 {} + self.write_data(byte); + } + + /// Write to the data register + fn write_data(&mut self, value: u8) { + unsafe { + let ptr = (ADDR as *mut u32).add(Self::DATA_OFFSET); + ptr.write_volatile(value as u32); + } + } + + /// Read from the Flag Register + fn get_flags(&mut self) -> u32 { + unsafe { + let ptr = (ADDR as *const u32).add(Self::FLAG_OFFSET); + ptr.read_volatile() + } + } + + /// Write to the control register + fn set_control(&mut self, value: u32) { + unsafe { + let ptr = (ADDR as *mut u32).add(Self::CONTROL_OFFSET); + ptr.write_volatile(value); + } + } +} + +impl core::fmt::Write for Uart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for b in s.bytes() { + self.write(b); + } + Ok(()) + } +} + +// End of file From 6be74d1a7b178829ae751a6b8f17df9665d07bbd Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 23 Jul 2024 16:24:08 +0100 Subject: [PATCH 3/4] Timer is working on QEMU Cortex-R5 --- qemu-cortex-r5-app/Cargo.lock | 1 - qemu-cortex-r5-app/Cargo.toml | 13 +- qemu-cortex-r5-app/build.rs | 2 + qemu-cortex-r5-app/commands.gdb | 3 +- qemu-cortex-r5-app/linker.ld | 2 +- qemu-cortex-r5-app/src/critical_section.rs | 34 ----- qemu-cortex-r5-app/src/lib.rs | 23 +-- qemu-cortex-r5-app/src/main.rs | 134 ++++++++++++++---- .../src/{virt_uart.rs => pl011_uart.rs} | 2 +- qemu-cortex-r5-app/src/pl190_vic.rs | 80 +++++++++++ qemu-cortex-r5-app/src/sp804_timer.rs | 87 ++++++++++++ .../src/tx_initialize_low_level.S | 7 +- 12 files changed, 302 insertions(+), 86 deletions(-) delete mode 100644 qemu-cortex-r5-app/src/critical_section.rs rename qemu-cortex-r5-app/src/{virt_uart.rs => pl011_uart.rs} (98%) create mode 100644 qemu-cortex-r5-app/src/pl190_vic.rs create mode 100644 qemu-cortex-r5-app/src/sp804_timer.rs diff --git a/qemu-cortex-r5-app/Cargo.lock b/qemu-cortex-r5-app/Cargo.lock index 165d69d..5c776cc 100644 --- a/qemu-cortex-r5-app/Cargo.lock +++ b/qemu-cortex-r5-app/Cargo.lock @@ -253,7 +253,6 @@ version = "0.1.0" dependencies = [ "byte-strings", "cc", - "critical-section", "embedded-alloc", "static_cell", "threadx-sys", diff --git a/qemu-cortex-r5-app/Cargo.toml b/qemu-cortex-r5-app/Cargo.toml index ff5183b..0b5d601 100644 --- a/qemu-cortex-r5-app/Cargo.toml +++ b/qemu-cortex-r5-app/Cargo.toml @@ -7,14 +7,19 @@ license = "MIT OR Apache-2.0" description = "A simple ARMv7-R demo application that runs ThreadX in QEMU and compiles with Ferrocene" [dependencies] -critical-section = { version = "1.1.2", features = ["restore-state-bool"] } embedded-alloc = "0.5.1" static_cell = "2.1.0" threadx-sys = { path = "../threadx-sys" } byte-strings = "0.3.1" -[profile.release] -opt-level = "s" - [build-dependencies] cc = "1.1.6" + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +lto = false +opt-level = 1 +overflow-checks = true diff --git a/qemu-cortex-r5-app/build.rs b/qemu-cortex-r5-app/build.rs index eeba1ed..ac2585d 100644 --- a/qemu-cortex-r5-app/build.rs +++ b/qemu-cortex-r5-app/build.rs @@ -228,6 +228,7 @@ fn main() -> Result<(), Box> { cc::Build::new() .include(&tx_common_inc) .include(&tx_port_inc) + .flag("-g") .define("TX_ENABLE_VFP_SUPPORT", "1") .files(TX_PORT_FILES.iter().map(|&s| tx_port_dir.join(s))) .files(TX_COMMON_FILES.iter().map(|&s| tx_common_dir.join(s))) @@ -236,6 +237,7 @@ fn main() -> Result<(), Box> { cc::Build::new() .include(&tx_common_inc) .include(&tx_port_inc) + .flag("-g") .file("src/tx_initialize_low_level.S") .compile("startup"); diff --git a/qemu-cortex-r5-app/commands.gdb b/qemu-cortex-r5-app/commands.gdb index bbfd2a5..9fdbd45 100644 --- a/qemu-cortex-r5-app/commands.gdb +++ b/qemu-cortex-r5-app/commands.gdb @@ -1,3 +1,4 @@ target extended-remote :1234 layout split - +break kmain +break qemu_cortex_r5_app::panic diff --git a/qemu-cortex-r5-app/linker.ld b/qemu-cortex-r5-app/linker.ld index cf182ab..bc03eaa 100644 --- a/qemu-cortex-r5-app/linker.ld +++ b/qemu-cortex-r5-app/linker.ld @@ -21,7 +21,7 @@ SECTIONS { /* Allocate room for stack. This must be big enough for the IRQ, FIQ, and SYS stack if nested interrupts are enabled. */ . = ALIGN(8) ; - . += 0x10000; + . += 0x100000; _sp = . - 16 ; _stack_top = ABSOLUTE(.) ; } > RAM diff --git a/qemu-cortex-r5-app/src/critical_section.rs b/qemu-cortex-r5-app/src/critical_section.rs deleted file mode 100644 index 2961d92..0000000 --- a/qemu-cortex-r5-app/src/critical_section.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Code that implements the `critical-section` traits on Cortex-R. - -struct SingleCoreCriticalSection; -critical_section::set_impl!(SingleCoreCriticalSection); - -/// Reads the CPU interrupt status bit from CPSR -/// -/// Returns true if interrupts enabled. -#[inline] -pub fn interrupts_enabled() -> bool { - const CPSR_I_BIT: u32 = 1 << 7; - let r: u32; - unsafe { - core::arch::asm!("mrs {}, CPSR", out(reg) r, options(nomem, nostack, preserves_flags)) - }; - r & CPSR_I_BIT != 0 -} - -unsafe impl critical_section::Impl for SingleCoreCriticalSection { - unsafe fn acquire() -> critical_section::RawRestoreState { - let was_active = interrupts_enabled(); - core::arch::asm!("cpsid i", options(nomem, nostack, preserves_flags)); - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); - was_active - } - - unsafe fn release(was_active: critical_section::RawRestoreState) { - // Only re-enable interrupts if they were enabled before the critical section. - if was_active { - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); - core::arch::asm!("cpsie i", options(nomem, nostack, preserves_flags)); - } - } -} diff --git a/qemu-cortex-r5-app/src/lib.rs b/qemu-cortex-r5-app/src/lib.rs index 8f48406..5298199 100644 --- a/qemu-cortex-r5-app/src/lib.rs +++ b/qemu-cortex-r5-app/src/lib.rs @@ -1,7 +1,8 @@ #![no_std] -pub mod critical_section; -pub mod virt_uart; +pub mod pl011_uart; +pub mod pl190_vic; +pub mod sp804_timer; core::arch::global_asm!( r#" @@ -14,15 +15,15 @@ core::arch::global_asm!( // Work around https://github.com/rust-lang/rust/issues/127269 .fpu vfp3-d16 -__vectors: - LDR pc, STARTUP @ Reset goes to startup function - LDR pc, UNDEFINED @ Undefined handler - LDR pc, SWI @ Software interrupt handler - LDR pc, PREFETCH @ Prefetch exception handler - LDR pc, ABORT @ Abort exception handler - LDR pc, RESERVED @ Reserved exception handler - LDR pc, IRQ @ IRQ interrupt handler - LDR pc, FIQ @ FIQ interrupt handler +_vectors: + LDR pc, STARTUP @ Reset goes to startup function 0x00 + LDR pc, UNDEFINED @ Undefined handler 0x04 + LDR pc, SWI @ Software interrupt handler 0x08 + LDR pc, PREFETCH @ Prefetch exception handler 0x0C + LDR pc, ABORT @ Abort exception handler 0x10 + LDR pc, RESERVED @ Reserved exception handler 0x14 + LDR pc, IRQ @ IRQ interrupt handler 0x18 + LDR pc, FIQ @ FIQ interrupt handler 0x1C STARTUP: .word _start @ Reset goes to C startup function diff --git a/qemu-cortex-r5-app/src/main.rs b/qemu-cortex-r5-app/src/main.rs index 7887677..416f21f 100644 --- a/qemu-cortex-r5-app/src/main.rs +++ b/qemu-cortex-r5-app/src/main.rs @@ -7,37 +7,58 @@ #![no_main] use byte_strings::c; -use core::{cell::RefCell, fmt::Write}; -use critical_section::Mutex; -use qemu_cortex_r5_app::virt_uart::Uart; +use core::{cell::UnsafeCell, fmt::Write as _, mem::MaybeUninit}; +use qemu_cortex_r5_app::{ + pl011_uart::Uart, + pl190_vic, + sp804_timer::{self, Timer0}, +}; use static_cell::StaticCell; static BUILD_SLUG: Option<&str> = option_env!("BUILD_SLUG"); -const DEMO_STACK_SIZE: usize = 1024; +const DEMO_STACK_SIZE: usize = 16384; +const DEMO_POOL_SIZE: usize = (DEMO_STACK_SIZE * 2) + 16384; static UART: GlobalUart = GlobalUart::new(); +unsafe impl Sync for GlobalUart {} + struct GlobalUart { - inner: Mutex>>>, + inner: UnsafeCell>>, + mutex: MaybeUninit>, } impl GlobalUart { /// Create a new, empty, global UART wrapper const fn new() -> GlobalUart { GlobalUart { - inner: Mutex::new(RefCell::new(None)), + inner: UnsafeCell::new(None), + mutex: MaybeUninit::uninit(), } } - /// Store a new UART at run-time + /// Store a new UART at run-time, and initialise the ThreadX mutex that + /// holds it. + /// + /// # Safety /// - /// Gives you back the old one, if any. - fn store(&self, uart: Uart<0x101f_1000>) -> Option> { - critical_section::with(|cs| { - let mut uart_ref = self.inner.borrow_ref_mut(cs); - uart_ref.replace(uart) - }) + /// Only call from init, not when threads are running, and only call it + /// once. + unsafe fn store(&self, uart: Uart<0x101f_1000>) { + // Init the ThreadX mutex + unsafe { + // init mutex + threadx_sys::_tx_mutex_create( + UnsafeCell::raw_get(self.mutex.as_ptr()), + "my_mutex\0".as_ptr() as _, + 0, + ); + // unsafely store UART object + let ptr = self.inner.get(); + let mut_ret = &mut *ptr; + *mut_ret = Some(uart); + } } } @@ -46,16 +67,40 @@ impl GlobalUart { impl core::fmt::Write for &GlobalUart { /// Write the string to the inner UART, with a lock held fn write_str(&mut self, s: &str) -> core::fmt::Result { - critical_section::with(|cs| { - let mut maybe_uart = self.inner.borrow_ref_mut(cs); - let Some(uart) = maybe_uart.as_mut() else { - return Err(core::fmt::Error); - }; - uart.write_str(s) - }) + // Grab ThreadX mutex + unsafe { + threadx_sys::_tx_mutex_get( + UnsafeCell::raw_get(self.mutex.as_ptr()), + threadx_sys::TX_WAIT_FOREVER, + ); + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire); + } + + // # Safety + // + // We hold the ThreadX Mutex at this point + let uart_option_ref = unsafe { &mut *self.inner.get() }; + let Some(uart) = uart_option_ref else { + return Err(core::fmt::Error); + }; + + let result = uart.write_str(s); + + // Drop the UART ref, then the threadX mutex + let _ = uart; + unsafe { + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release); + threadx_sys::_tx_mutex_put(UnsafeCell::raw_get(self.mutex.as_ptr())); + } + + result } } +/// Initialise our application. +/// +/// ThreadX calls this function during scheduler start-up. We use it to create +/// some threads. #[no_mangle] extern "C" fn tx_application_define(_first_unused_memory: *mut core::ffi::c_void) { _ = writeln!(&UART, "In tx_application_define()..."); @@ -66,7 +111,7 @@ extern "C" fn tx_application_define(_first_unused_memory: *mut core::ffi::c_void let byte_pool = { static BYTE_POOL: StaticCell = StaticCell::new(); - static BYTE_POOL_STORAGE: StaticCell<[u8; 32768]> = StaticCell::new(); + static BYTE_POOL_STORAGE: StaticCell<[u8; DEMO_POOL_SIZE]> = StaticCell::new(); let byte_pool = BYTE_POOL.uninit(); let byte_pool_storage = BYTE_POOL_STORAGE.uninit(); unsafe { @@ -74,7 +119,7 @@ extern "C" fn tx_application_define(_first_unused_memory: *mut core::ffi::c_void byte_pool.as_mut_ptr(), c!("byte-pool0").as_ptr() as *mut threadx_sys::CHAR, byte_pool_storage.as_mut_ptr() as *mut _, - core::mem::size_of_val(&BYTE_POOL_STORAGE) as u32, + DEMO_POOL_SIZE as u32, ); byte_pool.assume_init_mut() } @@ -139,8 +184,8 @@ extern "C" fn tx_application_define(_first_unused_memory: *mut core::ffi::c_void panic!("No space for stack"); } - static THREAD_STORAGE: StaticCell = StaticCell::new(); - let thread = THREAD_STORAGE.uninit(); + static THREAD_STORAGE2: StaticCell = StaticCell::new(); + let thread = THREAD_STORAGE2.uninit(); unsafe { let res = threadx_sys::_tx_thread_create( thread.as_mut_ptr(), @@ -190,14 +235,32 @@ extern "C" fn my_thread(value: u32) { /// It is called by the start-up code in `lib.rs`. #[no_mangle] pub extern "C" fn kmain() { - let uart0 = unsafe { Uart::new_uart0() }; - UART.store(uart0); + // Create a UART + let mut uart0 = unsafe { Uart::new_uart0() }; _ = writeln!( - &UART, + uart0, "Hello, this is version {}!", BUILD_SLUG.unwrap_or("unknown") ); - _ = writeln!(&UART, "Entering ThreadX kernel..."); + unsafe { + UART.store(uart0); + } + + let mut timer0 = unsafe { Timer0::new_timer0() }; + timer0.init( + 10_000, + sp804_timer::Mode::AutoReload, + sp804_timer::Interrupts::Enabled, + ); + + // Now we need to enable the Timer0 interrupt and connect it to IRQ on this core + // It's on PIC interrupt 4. + let mut vic = unsafe { pl190_vic::Interrupt::new() }; + vic.init(); + vic.enable_interrupt(4); + + timer0.start(); + unsafe { threadx_sys::_tx_initialize_kernel_enter(); } @@ -205,6 +268,21 @@ pub extern "C" fn kmain() { panic!("Kernel exited"); } +/// Called from the main interrupt handler +#[no_mangle] +unsafe extern "C" fn handle_interrupt() { + extern "C" { + fn _tx_timer_interrupt(); + } + + if Timer0::is_pending() { + unsafe { + _tx_timer_interrupt(); + } + Timer0::clear_interrupt(); + } +} + /// Called when the application raises an unrecoverable `panic!`. /// /// Prints the panic to the console and then exits QEMU using a semihosting diff --git a/qemu-cortex-r5-app/src/virt_uart.rs b/qemu-cortex-r5-app/src/pl011_uart.rs similarity index 98% rename from qemu-cortex-r5-app/src/virt_uart.rs rename to qemu-cortex-r5-app/src/pl011_uart.rs index fab913b..be3f1a6 100644 --- a/qemu-cortex-r5-app/src/virt_uart.rs +++ b/qemu-cortex-r5-app/src/pl011_uart.rs @@ -1,4 +1,4 @@ -//! A driver the Arm PL011 Uart +//! Code for the Arm PL011 Uart //! //! Written by Jonathan Pallant at Ferrous Systems //! diff --git a/qemu-cortex-r5-app/src/pl190_vic.rs b/qemu-cortex-r5-app/src/pl190_vic.rs new file mode 100644 index 0000000..13f60c7 --- /dev/null +++ b/qemu-cortex-r5-app/src/pl190_vic.rs @@ -0,0 +1,80 @@ +//! Code for the Arm PL190 Vector Interrupt Controller +//! +//! Written by Jonathan Pallant at Ferrous Systems +//! +//! Copyright (c) Ferrous Systems, 2024 + +/// A driver for a virtual PL190 Vector Interrupt Controller +/// +/// It might skip some important initialisation, but it works on QEMU. +pub struct Interrupt(); + +impl Interrupt<0x10140000> { + /// Create an interrupt controller driver + /// + /// # Safety + /// + /// Only construct one object per Interrupt Controller at any given time. + pub unsafe fn new() -> Interrupt<0x10140000> { + Interrupt() + } +} + +impl Interrupt { + const BASE_PTR: *mut u32 = ADDR as *mut u32; + + // These are in 32-bit word offsets (so * 4 to get byte offsets) + + const IRQ_STATUS_OFFSET: usize = 0x00 >> 2; + const INT_SELECT_OFFSET: usize = 0x0C >> 2; + const INT_EN_OFFSET: usize = 0x10 >> 2; + const DEF_VECT_ADDR_OFFSET: usize = 0x34 >> 2; + const VECT_CTRL_N_START_OFFSET: usize = 0x200 >> 2; + + const CNTL_ENABLE: u32 = 1 << 5; + + const NUM_PRIOS: u8 = 16; + const NUM_IRQS: u8 = 32; + + /// Get the address of the control register for a particular interrupt vector. + const fn prio_control_addr(prio: u8) -> *mut u32 { + if prio >= Self::NUM_PRIOS { + panic!("bad prio"); + } + unsafe { Self::BASE_PTR.add(Self::VECT_CTRL_N_START_OFFSET + (prio as usize)) } + } + + /// Initialise the interrupt controller by setting up all the vectors + pub fn init(&mut self) { + unsafe { + // Set the first 16 vectors to point to the first 16 sources + for i in 0..Self::NUM_PRIOS { + Self::prio_control_addr(i).write_volatile(Self::CNTL_ENABLE | u32::from(i)); + } + // Setup default vector - points at IRQ handler in vector table + Self::BASE_PTR + .add(Self::DEF_VECT_ADDR_OFFSET) + .write_volatile(0x18); + // Every interrupt is an IRQ not an FIQ + Self::BASE_PTR + .add(Self::INT_SELECT_OFFSET) + .write_volatile(0x0000_0000); + } + } + + pub fn enable_interrupt(&mut self, interrupt: u8) { + if interrupt > Self::NUM_IRQS { + panic!("Bad IRQ"); + } + + unsafe { + Self::BASE_PTR + .add(Self::INT_EN_OFFSET) + .write_volatile(1 << interrupt); + } + } + + pub fn read_interrupt_status() -> u32 { + unsafe { Self::BASE_PTR.add(Self::IRQ_STATUS_OFFSET).read_volatile() } + } +} diff --git a/qemu-cortex-r5-app/src/sp804_timer.rs b/qemu-cortex-r5-app/src/sp804_timer.rs new file mode 100644 index 0000000..6d08826 --- /dev/null +++ b/qemu-cortex-r5-app/src/sp804_timer.rs @@ -0,0 +1,87 @@ +//! Code for the Arm SP804 Timer +//! +//! Written by Jonathan Pallant at Ferrous Systems +//! +//! Copyright (c) Ferrous Systems, 2024 + +/// Supported timer modes +pub enum Mode { + AutoReload = 0, + SingleShot = 1, +} + +/// Supported interrupt options +pub enum Interrupts { + Disabled = 0, + Enabled = 1 << 5, +} + +pub type Timer0 = Timer<0x101e_2000>; + +/// A driver for a virtual SP804 Timer +/// +/// It probably skips some important initialisation, but it works on QEMU. +pub struct Timer(); + +impl Timer0 { + /// Create a new Timer object for Timer0 + /// + /// # Safety + /// + /// Only construct one object per Timer at any given time. + pub unsafe fn new_timer0() -> Self { + Timer() + } +} + +impl Timer { + const BASE_PTR: *mut u32 = ADDR as *mut u32; + + const LOAD_REGISTER: usize = 0x00 >> 2; + const CTRL_OFFSET: usize = 0x08 >> 2; + const ICR_OFFSET: usize = 0x0C >> 2; + const MIS_OFFSET: usize = 0x14 >> 2; + + const CTRL_TIMERSIZE_32: u32 = 1 << 1; + const CTRL_TIMERMODE: u32 = 1 << 6; + const CTRL_TIMEREN: u32 = 1 << 7; + + /// Initialise the timer + pub fn init(&mut self, load_value: u32, mode: Mode, interrupt: Interrupts) { + unsafe { + Self::BASE_PTR + .add(Self::LOAD_REGISTER) + .write_volatile(load_value); + let settings = + Self::CTRL_TIMERSIZE_32 | Self::CTRL_TIMERMODE | mode as u32 | interrupt as u32; + Self::BASE_PTR + .add(Self::CTRL_OFFSET) + .write_volatile(settings); + } + } + + /// Start the timer + pub fn start(&mut self) { + unsafe { + let time1_ctrl = Self::BASE_PTR.add(2); + let mut temp = time1_ctrl.read_volatile(); + temp |= Self::CTRL_TIMEREN; + time1_ctrl.write_volatile(temp); + } + } + + pub fn is_pending() -> bool { + let value = unsafe { Self::BASE_PTR.add(Self::MIS_OFFSET).read_volatile() }; + (value & 1) != 0 + } + + /// Clear a pending interrupt + pub fn clear_interrupt() { + // Write anything here to clear the interrupt + unsafe { + Self::BASE_PTR.add(Self::ICR_OFFSET).write_volatile(1); + } + } +} + +// End of file diff --git a/qemu-cortex-r5-app/src/tx_initialize_low_level.S b/qemu-cortex-r5-app/src/tx_initialize_low_level.S index a347127..ca36af6 100644 --- a/qemu-cortex-r5-app/src/tx_initialize_low_level.S +++ b/qemu-cortex-r5-app/src/tx_initialize_low_level.S @@ -232,11 +232,8 @@ __tx_irq_processing_return: BL _tx_thread_irq_nesting_start #endif @ -@ /* For debug purpose, execute the timer interrupt processing here. In -@ a real system, some kind of status indication would have to be checked -@ before the timer interrupt handler could be called. */ -@ - BL _tx_timer_interrupt @ Timer interrupt handler + /* Use Rust to handle the interrupt */ + BL handle_interrupt @ @ @ /* If interrupt nesting was started earlier, the end of interrupt nesting From cb78435904075b84c9a25c31c46dbcd7e88c58d1 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 23 Jul 2024 17:19:14 +0100 Subject: [PATCH 4/4] Complying with the REUSE specification --- qemu-cortex-r5-app/.cargo/config.toml | 3 +++ qemu-cortex-r5-app/.gitignore | 3 +++ qemu-cortex-r5-app/.vscode/settings.json | 3 --- qemu-cortex-r5-app/Cargo.lock.license | 2 ++ qemu-cortex-r5-app/Cargo.toml | 3 +++ qemu-cortex-r5-app/commands.gdb.license | 2 ++ qemu-cortex-r5-app/linker.ld | 7 +++++++ qemu-cortex-r5-app/src/lib.rs | 5 +++++ qemu-cortex-r5-app/src/pl011_uart.rs | 7 +++---- qemu-cortex-r5-app/src/pl190_vic.rs | 7 +++---- qemu-cortex-r5-app/src/sp804_timer.rs | 8 ++++---- 11 files changed, 35 insertions(+), 15 deletions(-) delete mode 100644 qemu-cortex-r5-app/.vscode/settings.json create mode 100644 qemu-cortex-r5-app/Cargo.lock.license create mode 100644 qemu-cortex-r5-app/commands.gdb.license diff --git a/qemu-cortex-r5-app/.cargo/config.toml b/qemu-cortex-r5-app/.cargo/config.toml index fa7148c..29a7196 100644 --- a/qemu-cortex-r5-app/.cargo/config.toml +++ b/qemu-cortex-r5-app/.cargo/config.toml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +# SPDX-License-Identifier: MIT OR Apache-2.0 + [target.armv7r-none-eabihf] rustflags = [ "-Clink-arg=-Tlinker.ld", diff --git a/qemu-cortex-r5-app/.gitignore b/qemu-cortex-r5-app/.gitignore index ea8c4bf..a0c89ad 100644 --- a/qemu-cortex-r5-app/.gitignore +++ b/qemu-cortex-r5-app/.gitignore @@ -1 +1,4 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +# SPDX-License-Identifier: CC0-1.0 + /target diff --git a/qemu-cortex-r5-app/.vscode/settings.json b/qemu-cortex-r5-app/.vscode/settings.json deleted file mode 100644 index 7d7a538..0000000 --- a/qemu-cortex-r5-app/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "rust-analyzer.procMacro.enable": false -} diff --git a/qemu-cortex-r5-app/Cargo.lock.license b/qemu-cortex-r5-app/Cargo.lock.license new file mode 100644 index 0000000..16e4e62 --- /dev/null +++ b/qemu-cortex-r5-app/Cargo.lock.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +# SPDX-License-Identifier: CC0-1.0 diff --git a/qemu-cortex-r5-app/Cargo.toml b/qemu-cortex-r5-app/Cargo.toml index 0b5d601..766c864 100644 --- a/qemu-cortex-r5-app/Cargo.toml +++ b/qemu-cortex-r5-app/Cargo.toml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +# SPDX-License-Identifier: MIT OR Apache-2.0 + [package] name = "qemu-cortex-r5-app" version = "0.1.0" diff --git a/qemu-cortex-r5-app/commands.gdb.license b/qemu-cortex-r5-app/commands.gdb.license new file mode 100644 index 0000000..16e4e62 --- /dev/null +++ b/qemu-cortex-r5-app/commands.gdb.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +# SPDX-License-Identifier: CC0-1.0 diff --git a/qemu-cortex-r5-app/linker.ld b/qemu-cortex-r5-app/linker.ld index bc03eaa..f7fa5ac 100644 --- a/qemu-cortex-r5-app/linker.ld +++ b/qemu-cortex-r5-app/linker.ld @@ -1,3 +1,10 @@ +/* + * Linker script for running ThreadX/Rust on QEMU's Versatile AB with a Cortex-R5 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems + * SPDX-License-Identifier: MIT OR Apache-2.0 +*/ + MEMORY { RAM : ORIGIN = 0, LENGTH = 0x1000000 } diff --git a/qemu-cortex-r5-app/src/lib.rs b/qemu-cortex-r5-app/src/lib.rs index 5298199..4bccf1c 100644 --- a/qemu-cortex-r5-app/src/lib.rs +++ b/qemu-cortex-r5-app/src/lib.rs @@ -1,3 +1,8 @@ +//! Common code for the ThreadX/Rust on Cortex-R5 demo + +// SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +// SPDX-License-Identifier: MIT OR Apache-2.0 + #![no_std] pub mod pl011_uart; diff --git a/qemu-cortex-r5-app/src/pl011_uart.rs b/qemu-cortex-r5-app/src/pl011_uart.rs index be3f1a6..1ef09f6 100644 --- a/qemu-cortex-r5-app/src/pl011_uart.rs +++ b/qemu-cortex-r5-app/src/pl011_uart.rs @@ -1,8 +1,7 @@ //! Code for the Arm PL011 Uart -//! -//! Written by Jonathan Pallant at Ferrous Systems -//! -//! Copyright (c) Ferrous Systems, 2024 + +// SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +// SPDX-License-Identifier: MIT OR Apache-2.0 /// A driver for a virtual PL011 Uart /// diff --git a/qemu-cortex-r5-app/src/pl190_vic.rs b/qemu-cortex-r5-app/src/pl190_vic.rs index 13f60c7..b05d8f0 100644 --- a/qemu-cortex-r5-app/src/pl190_vic.rs +++ b/qemu-cortex-r5-app/src/pl190_vic.rs @@ -1,8 +1,7 @@ //! Code for the Arm PL190 Vector Interrupt Controller -//! -//! Written by Jonathan Pallant at Ferrous Systems -//! -//! Copyright (c) Ferrous Systems, 2024 + +// SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +// SPDX-License-Identifier: MIT OR Apache-2.0 /// A driver for a virtual PL190 Vector Interrupt Controller /// diff --git a/qemu-cortex-r5-app/src/sp804_timer.rs b/qemu-cortex-r5-app/src/sp804_timer.rs index 6d08826..9ea4d3c 100644 --- a/qemu-cortex-r5-app/src/sp804_timer.rs +++ b/qemu-cortex-r5-app/src/sp804_timer.rs @@ -1,8 +1,7 @@ //! Code for the Arm SP804 Timer -//! -//! Written by Jonathan Pallant at Ferrous Systems -//! -//! Copyright (c) Ferrous Systems, 2024 + +// SPDX-FileCopyrightText: Copyright (c) 2024 Ferrous Systems +// SPDX-License-Identifier: MIT OR Apache-2.0 /// Supported timer modes pub enum Mode { @@ -16,6 +15,7 @@ pub enum Interrupts { Enabled = 1 << 5, } +/// Timer0 on an Arm Versatile Application Board. pub type Timer0 = Timer<0x101e_2000>; /// A driver for a virtual SP804 Timer