Skip to content

Commit

Permalink
Merge pull request #166 from ferrous-systems/ferrocene-example-fixes
Browse files Browse the repository at this point in the history
Ferrocene example fixes and Aarch64 Armv8-A Heap Demo
  • Loading branch information
miguelraz authored Jun 25, 2024
2 parents 866be2b + 724df10 commit d3e2ab3
Show file tree
Hide file tree
Showing 54 changed files with 4,950 additions and 156 deletions.
2 changes: 2 additions & 0 deletions example-code/qemu-aarch64v8a/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
rustflags = [
"-Clink-arg=-Tlinker.ld",
]
# QEMU Aarch64 boots in EL1 by default
# Add "-machine virtualization=on" to boot in EL2
runner = "qemu-system-aarch64 -machine virt -cpu cortex-a57 -semihosting -nographic -kernel"

[build]
Expand Down
28 changes: 27 additions & 1 deletion example-code/qemu-aarch64v8a/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion example-code/qemu-aarch64v8a/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
[package]
name = "basic-rust"
name = "qemu-aarch64v8a"
version = "0.1.0"
edition = "2021"
authors = ["Ferrous Systems"]
license = "MIT OR Apache-2.0"
description = "A simple Aarch64 demo application that runs in QEMU and compiles with Ferrocene"

[dependencies]
critical-section = { version = "1.1.2", features = ["restore-state-bool"] }
embedded-alloc = "0.5.1"

[profile.release]
opt-level = "s"

[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"
128 changes: 86 additions & 42 deletions example-code/qemu-aarch64v8a/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,34 @@ You must first install Ferrocene by executing `criticalup install` inside this
folder. This will require a valid CriticalUp token - please see the [CriticalUp
documentation](https://criticalup.ferrocene.dev).

To view the project inside VS Code, set your `RUSTC` environment variable to
point at your `criticalup` rustc proxy. On macOS, that can be done with:

```bash
RUSTC=~/Library/Application\ Support/criticalup/bin/rustc code .
```

## Demo contents

This demo is a simple application designed to run inside a QEMU virtual machine.
This demo provides a few simple applications, designed to run inside a QEMU
virtual machine that is emulating an Aarch64 Arm Cortex-A system. Both demos:

1. It prints "Hello, world!" to the first QEMU UART, which is typically
1. Print "Hello, world!" to the first QEMU UART, which is typically
connected to the console when you run QEMU.
2. It then causes a `panic!` which causes the custom panic handler to execute.
3. The the panic handler also prints to the same UART.
4. The panic handler exits QEMU using a semihosting operation that QEMU
2. Print some floating point numbers in a grid (the 1 though 10 times tables).
3. Causes a `panic!` which causes the custom panic handler to execute.
4. The the panic handler also prints to the same UART.
5. The panic handler exits QEMU using a semihosting operation that QEMU
understands to mean "exit QEMU".

There are two binaries in `./src/bin`:

* `no_heap` runs with no heap
* `with_heap` sets up a heap allocator and uses the `format!` macro to generate
heap-allocated strings, which it then prints.

Both binaries should produce the same output.

## Building and Running with `cargo`

Ferrocene compiles standard Rust source code, and so this project has also been
Expand All @@ -40,28 +57,26 @@ the linker script to the `cargo` temporary output directory where the linker
will look for it.

The compiled outputs will go into `./target/aarch64-none-eabi/<profile>`, where
`<profile>` is `debug` or `release`. The binary is called `basic-rust`, because
`<profile>` is `debug` or `release`. The binary is called `qemu-aarch64v8a`, because
that's the name given in the `Cargo.toml` file.

```console
$ criticalup run cargo build --release
Finished release [optimized] target(s) in 0.00s
$ criticalup run cargo run --release
Compiling basic-rust v0.1.0 (/Users/jonathan/work/basic-rust)
$ criticalup run cargo run --release --bin no_heap
Compiling qemu-aarch64v8a v0.1.0 (/Users/jonathan/work/qemu-aarch64v8a)
Finished release [optimized] target(s) in 0.16s
Running `qemu-system-aarch64 -machine virt -cpu cortex-a57 -semihosting -nographic -kernel target/aarch64-unknown-none/release/basic-rust`
Running `qemu-system-aarch64 -machine virt -cpu cortex-a57 -semihosting -nographic -kernel target/aarch64-unknown-none/release/qemu-aarch64v8a`
Hello, this is Rust!
1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
2.00 4.00 6.00 8.00 10.00 12.00 14.00 16.00 18.00 20.00
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00 27.00 30.00
4.00 8.00 12.00 16.00 20.00 24.00 28.00 32.00 36.00 40.00
5.00 10.00 15.00 20.00 25.00 30.00 35.00 40.00 45.00 50.00
6.00 12.00 18.00 24.00 30.00 36.00 42.00 48.00 54.00 60.00
7.00 14.00 21.00 28.00 35.00 42.00 49.00 56.00 63.00 70.00
8.00 16.00 24.00 32.00 40.00 48.00 56.00 64.00 72.00 80.00
9.00 18.00 27.00 36.00 45.00 54.00 63.00 72.00 81.00 90.00
10.00 20.00 30.00 40.00 50.00 60.00 70.00 80.00 90.00 100.00
PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), location: Location { file: "src/main.rs", line: 40, col: 5 }, can_unwind: true, force_no_backtrace: false }
1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
2.00 4.00 6.00 8.00 10.00 12.00 14.00 16.00 18.00 20.00
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00 27.00 30.00
4.00 8.00 12.00 16.00 20.00 24.00 28.00 32.00 36.00 40.00
5.00 10.00 15.00 20.00 25.00 30.00 35.00 40.00 45.00 50.00
6.00 12.00 18.00 24.00 30.00 36.00 42.00 48.00 54.00 60.00
7.00 14.00 21.00 28.00 35.00 42.00 49.00 56.00 63.00 70.00
8.00 16.00 24.00 32.00 40.00 48.00 56.00 64.00 72.00 80.00
9.00 18.00 27.00 36.00 45.00 54.00 63.00 72.00 81.00 90.00
10.00 20.00 30.00 40.00 50.00 60.00 70.00 80.00 90.00 100.00
PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), location: Location { file: "src/bin/with_heap.rs", line: 61, col: 5 }, can_unwind: true, force_no_backtrace: false }
```

## Building and Running without `cargo`
Expand All @@ -73,37 +88,66 @@ This demo includes a [`build.sh`](./build.sh) shell script to build our binary
by calling `rustc` directly. This script will:

1. Find the location of the tools it needs
2. Call `criticalup run rustc` to compile `src/main.rs` into `<output>/basic-rust`
3. Generate `asm` and `map` files from the `<output>/basic-rust` using LLVM
2. Call `criticalup run rustc --crate-type=lib` repeatedly, to compile all the
various dependencies (from the `./vendor` folder)
3. Call `criticalup run rustc --crate-type=bin` to compile `src/bin/no_heap.rs`
into `<output>/no_heap`
4. Generate `asm` and `map` files from the `<output>/no_heap` binary using LLVM
tools shipped with Ferrocene
5. Compile the `with_heap` binary in the same fashion

The outputs will go into `./target/production` and the binary is called
`basic-rust`. You can choose any suitable directory, but avoid clashing with
anything you do using `cargo`.
The outputs will go into `./target/production` and the binaries are called
`no_heap` and `with_heap`. You can choose any suitable directory, but avoid
clashing with anything you do using `cargo`.

```console
$ ./build.sh
Running rustc...
Generating asm...
Generating map...
Running rustc for critical-section
Running rustc for linked-list-allocator
Running rustc for embedded-alloc
Running rustc for lib...
Running rustc for no_heap...
Generating asm for no_heap...
Generating map for no_heap...
Running rustc for with_heap...
Generating asm for with_heap...
Generating map for with_heap...
$ qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-semihosting \
-nographic \
-kernel ./target/production/basic-rust
-kernel target/production/with_heap
Hello, this is Rust!
1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
2.00 4.00 6.00 8.00 10.00 12.00 14.00 16.00 18.00 20.00
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00 27.00 30.00
4.00 8.00 12.00 16.00 20.00 24.00 28.00 32.00 36.00 40.00
5.00 10.00 15.00 20.00 25.00 30.00 35.00 40.00 45.00 50.00
6.00 12.00 18.00 24.00 30.00 36.00 42.00 48.00 54.00 60.00
7.00 14.00 21.00 28.00 35.00 42.00 49.00 56.00 63.00 70.00
8.00 16.00 24.00 32.00 40.00 48.00 56.00 64.00 72.00 80.00
9.00 18.00 27.00 36.00 45.00 54.00 63.00 72.00 81.00 90.00
10.00 20.00 30.00 40.00 50.00 60.00 70.00 80.00 90.00 100.00
PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), location: Location { file: "src/bin/with_heap.rs", line: 61, col: 5 }, can_unwind: true, force_no_backtrace: false }
```

Rather than type out the full QEMU command line, you can also use `qemu.sh`:

```console
$ ./qemu.sh ./target/production/with_heap
Hello, this is Rust!
1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
2.00 4.00 6.00 8.00 10.00 12.00 14.00 16.00 18.00 20.00
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00 27.00 30.00
4.00 8.00 12.00 16.00 20.00 24.00 28.00 32.00 36.00 40.00
5.00 10.00 15.00 20.00 25.00 30.00 35.00 40.00 45.00 50.00
6.00 12.00 18.00 24.00 30.00 36.00 42.00 48.00 54.00 60.00
7.00 14.00 21.00 28.00 35.00 42.00 49.00 56.00 63.00 70.00
8.00 16.00 24.00 32.00 40.00 48.00 56.00 64.00 72.00 80.00
9.00 18.00 27.00 36.00 45.00 54.00 63.00 72.00 81.00 90.00
10.00 20.00 30.00 40.00 50.00 60.00 70.00 80.00 90.00 100.00
PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), location: Location { file: "src/main.rs", line: 40, col: 5 }, can_unwind: true, force_no_backtrace: false }
1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
2.00 4.00 6.00 8.00 10.00 12.00 14.00 16.00 18.00 20.00
3.00 6.00 9.00 12.00 15.00 18.00 21.00 24.00 27.00 30.00
4.00 8.00 12.00 16.00 20.00 24.00 28.00 32.00 36.00 40.00
5.00 10.00 15.00 20.00 25.00 30.00 35.00 40.00 45.00 50.00
6.00 12.00 18.00 24.00 30.00 36.00 42.00 48.00 54.00 60.00
7.00 14.00 21.00 28.00 35.00 42.00 49.00 56.00 63.00 70.00
8.00 16.00 24.00 32.00 40.00 48.00 56.00 64.00 72.00 80.00
9.00 18.00 27.00 36.00 45.00 54.00 63.00 72.00 81.00 90.00
10.00 20.00 30.00 40.00 50.00 60.00 70.00 80.00 90.00 100.00
PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), location: Location { file: "src/bin/with_heap.rs", line: 61, col: 5 }, can_unwind: true, force_no_backtrace: false }
```

## License
Expand Down
103 changes: 91 additions & 12 deletions example-code/qemu-aarch64v8a/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,102 @@
set -euo pipefail

TARGET_DIR=target/production
OUTPUT_BINARY=${TARGET_DIR}/basic-rust
RUSTC=$(criticalup which rustc)
SYSROOT=$(criticalup run rustc --print sysroot)
OBJDUMP=$(ls "${SYSROOT}"/lib/rustlib/*/bin/llvm-objdump)
OUTPUT_MAP=${TARGET_DIR}/basic-rust.map
OUTPUT_ASM=${TARGET_DIR}/basic-rust.asm
RUSTC_FLAGS="--target aarch64-unknown-none -Copt-level=s"

WITH_HEAP_OUTPUT_BINARY=${TARGET_DIR}/with_heap
WITH_HEAP_OUTPUT_MAP=${TARGET_DIR}/with_heap.map
WITH_HEAP_OUTPUT_ASM=${TARGET_DIR}/with_heap.asm
NO_HEAP_OUTPUT_BINARY=${TARGET_DIR}/no_heap
NO_HEAP_OUTPUT_MAP=${TARGET_DIR}/no_heap.map
NO_HEAP_OUTPUT_ASM=${TARGET_DIR}/no_heap.asm

rm -rf ${TARGET_DIR}
mkdir -p ${TARGET_DIR}
echo Running rustc...
"${RUSTC}" --target aarch64-unknown-none \

# ############################################################################
echo "Running rustc for critical-section"
# ############################################################################
"${RUSTC}" ${RUSTC_FLAGS} \
--crate-type=lib \
--crate-name=critical_section \
--emit=dep-info,metadata,link \
--out-dir ${TARGET_DIR} \
--cfg 'feature="restore-state-bool"' \
--edition 2021 \
vendor/critical-section/src/lib.rs

# ############################################################################
echo "Running rustc for linked-list-allocator"
# ############################################################################
"${RUSTC}" ${RUSTC_FLAGS} \
--crate-type=lib \
--crate-name=linked_list_allocator \
--emit=dep-info,metadata,link \
--out-dir ${TARGET_DIR} \
-L ${TARGET_DIR} \
--edition 2018 \
vendor/linked_list_allocator/src/lib.rs

# ############################################################################
echo "Running rustc for embedded-alloc"
# ############################################################################
"${RUSTC}" ${RUSTC_FLAGS} \
--crate-type=lib \
--crate-name=embedded_alloc \
--emit=dep-info,metadata,link \
--out-dir ${TARGET_DIR} \
-L ${TARGET_DIR} \
--extern critical_section=${TARGET_DIR}/libcritical_section.rmeta \
--extern linked_list_allocator=${TARGET_DIR}/liblinked_list_allocator.rmeta \
--edition 2018 \
vendor/embedded-alloc/src/lib.rs

# ############################################################################
echo Running rustc for lib...
# ############################################################################
"${RUSTC}" ${RUSTC_FLAGS} \
--crate-type=lib \
--crate-name=qemu_aarch64v8a \
--emit=dep-info,metadata,link \
--out-dir ${TARGET_DIR} \
-L ${TARGET_DIR} \
--edition 2021 \
--extern critical_section=${TARGET_DIR}/libcritical_section.rmeta \
--extern embedded_alloc=${TARGET_DIR}/libembedded_alloc.rmeta \
src/lib.rs

# ############################################################################
echo Running rustc for no_heap...
# ############################################################################
"${RUSTC}" ${RUSTC_FLAGS} \
--crate-type=bin \
-Clink-arg=-Tlinker.ld \
--edition 2021 \
-L ${TARGET_DIR} \
--extern qemu_aarch64v8a=${TARGET_DIR}/libqemu_aarch64v8a.rlib \
-o ${NO_HEAP_OUTPUT_BINARY} \
src/bin/no_heap.rs
echo Generating asm for no_heap...
"${OBJDUMP}" -Cd ${NO_HEAP_OUTPUT_BINARY} > ${NO_HEAP_OUTPUT_ASM}
echo Generating map for no_heap...
"${OBJDUMP}" -Ct ${NO_HEAP_OUTPUT_BINARY} > ${NO_HEAP_OUTPUT_MAP}

# ############################################################################
echo Running rustc for with_heap...
# ############################################################################
"${RUSTC}" ${RUSTC_FLAGS} \
-Clink-arg=-Tlinker.ld \
-Copt-level=s \
--edition 2021 \
-o ${OUTPUT_BINARY} \
src/main.rs
echo Generating asm...
"${OBJDUMP}" -Cd ${OUTPUT_BINARY} > ${OUTPUT_ASM}
echo Generating map...
"${OBJDUMP}" -Ct ${OUTPUT_BINARY} > ${OUTPUT_MAP}
-L ${TARGET_DIR} \
--extern qemu_aarch64v8a=${TARGET_DIR}/libqemu_aarch64v8a.rlib \
--extern embedded_alloc=${TARGET_DIR}/libembedded_alloc.rlib \
-o ${WITH_HEAP_OUTPUT_BINARY} \
src/bin/with_heap.rs
echo Generating asm for with_heap...
"${OBJDUMP}" -Cd ${WITH_HEAP_OUTPUT_BINARY} > ${WITH_HEAP_OUTPUT_ASM}
echo Generating map for with_heap...
"${OBJDUMP}" -Ct ${WITH_HEAP_OUTPUT_BINARY} > ${WITH_HEAP_OUTPUT_MAP}

2 changes: 1 addition & 1 deletion example-code/qemu-aarch64v8a/qemu.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/sh

TARGET_DIR=target/production
BINARY=${TARGET_DIR}/basic-rust
BINARY=${1:-${TARGET_DIR}/no_heap}
qemu-system-aarch64 -machine virt -cpu cortex-a57 -semihosting -nographic -kernel ${BINARY}
Loading

0 comments on commit d3e2ab3

Please sign in to comment.