Merge #195
195: README: Update to better describe Tock kernel version support r=alistair23 a=alistair23
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Co-authored-by: Alistair Francis <alistair.francis@wdc.com>
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..45ddcde
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "tock"]
+ path = tock
+ url = https://github.com/tock/tock.git
diff --git a/.travis.yml b/.travis.yml
index 66cee0b..52e5d38 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,36 +13,8 @@
cache: cargo
-# Once Travis supports a version of Ubuntu that inlcudes QEMU 5.1+
-# we can apt install QEMU for RISC-V.
-# Until then we need to build it ourselves
-before_install:
- # - sudo apt-get -y install qemu-system-misc
- # addons:
- # apt:
- # update: true
- - git clone https://github.com/alistair23/qemu.git -b riscv-tock.next
- - pushd qemu
- - ./configure --target-list=riscv32-softmmu
- - make -j8
- - sudo ln -s $PWD/riscv32-softmmu/qemu-system-riscv32 /usr/bin/
- - popd
-
install:
- - make setup
- # Build Tock, it needs to be outside of the libtock-rs source
- - pushd ../
- - git clone https://github.com/tock/tock.git
- - cd tock/boards/hifive1
- # Use a known working version of Tock
- - git checkout 152189fe077aea955332ee3c28ccbee519d8b072
- - make
- - popd
+ - make -j8 setup
script:
- make test
- # Run a QEMU instance of the HiFive1 app
- - PLATFORM=hifive1 cargo rrv32imac --example libtock_test --features=alloc --features=__internal_disable_gpio_in_integration_test
- - pushd test-runner
- - cargo run
- - popd
diff --git a/Cargo.toml b/Cargo.toml
index ee68117..b8e0bec 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,8 +58,10 @@
debug = true
[workspace]
+exclude = [ "tock" ]
members = [
"codegen",
"core",
- "test-runner"
+ "test-runner",
+ "tools/print-sizes",
]
diff --git a/Makefile b/Makefile
index f1f6dd5..d205cc7 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@
@echo " - opentitan"
@echo " - hifive1"
@echo " - nrf52"
+ @echo " - apollo3"
@echo
@echo "Run 'make setup' to setup Rust to build libtock-rs."
@echo "Run 'make <board>' to build libtock-rs for that board"
@@ -21,6 +22,7 @@
@echo " Set the FEATURES flag to enable features"
@echo "Run 'make flash-<board> EXAMPLE=<>' to flash EXAMPLE to that board"
@echo "Run 'make test' to test any local changes you have made"
+ @echo "Run 'make print-sizes' to print size data for the example binaries"
ifdef FEATURES
features=--features=$(FEATURES)
@@ -31,7 +33,7 @@
endif
.PHONY: setup
-setup:
+setup: setup-qemu
rustup target add thumbv7em-none-eabi
rustup target add riscv32imac-unknown-none-elf
rustup target add riscv32imc-unknown-none-elf
@@ -40,20 +42,45 @@
cargo install elf2tab --version 0.4.0
cargo install stack-sizes
+# Sets up QEMU in the tock/ directory. We use Tock's QEMU which may contain
+# patches to better support boards that Tock supports.
+.PHONY: setup-qemu
+setup-qemu:
+ $(MAKE) -C tock emulation-setup
+
+# Builds a Tock kernel for the HiFive board for use by QEMU tests.
+.PHONY: kernel-hifive
+kernel-hifive:
+ $(MAKE) -C tock/boards/hifive1 \
+ $(CURDIR)/tock/target/riscv32imac-unknown-none-elf/release/hifive1.elf
+
+# Prints out the sizes of the example binaries.
+.PHONY: print-sizes
+print-sizes: examples
+ cargo run --release -p print-sizes
+
+# Runs the libtock_test tests in QEMU on a simulated HiFive board.
+.PHONY: test-qemu-hifive
+test-qemu-hifive: kernel-hifive setup-qemu
+ PLATFORM=hifive1 cargo rrv32imac --example libtock_test --features=alloc \
+ --features=__internal_disable_gpio_in_integration_test
+ cargo run -p test-runner
+
.PHONY: examples
examples:
- PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples
+ PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples -p libtock -p libtock-core
PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples --features=alloc
PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --example panic --features=custom_panic_handler,custom_alloc_error_handler
PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --example alloc_error --features=alloc,custom_alloc_error_handler
- PLATFORM=opentitan cargo build --release --target=riscv32imc-unknown-none-elf --examples # Important: This is testing a platform without atomics support
+ # Important: This tests a platform without atomic instructions.
+ PLATFORM=opentitan cargo build --release --target=riscv32imc-unknown-none-elf --examples -p libtock -p libtock-core
.PHONY: test
-test:
+test: examples test-qemu-hifive
PLATFORM=nrf52 cargo fmt --all -- --check
PLATFORM=nrf52 cargo clippy --workspace --all-targets
PLATFORM=nrf52 cargo test --workspace
- make examples
+ echo '[ SUCCESS ] libtock-rs tests pass'
.PHONY: analyse-stack-sizes
analyse-stack-sizes:
@@ -109,5 +136,5 @@
.PHONY: clean
clean:
- rm -rf target
- rm Cargo.lock
+ cargo clean
+ $(MAKE) -C tock clean
diff --git a/README.md b/README.md
index 8684d4c..72506cd 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@
1. Clone the repository:
```shell
- git clone https://github.com/tock/libtock-rs
+ git clone --recursive https://github.com/tock/libtock-rs
cd libtock-rs
```
@@ -108,7 +108,7 @@
## License
-Licensed under either of
+libtock-rs is licensed under either of
- Apache License, Version 2.0
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
@@ -117,6 +117,8 @@
at your option.
+Submodules have their own licenses.
+
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
diff --git a/boards/layout_nrf52.ld b/boards/layout_nrf52.ld
index 419a0bc..40cdb10 100644
--- a/boards/layout_nrf52.ld
+++ b/boards/layout_nrf52.ld
@@ -3,7 +3,7 @@
MEMORY {
/* The application region is 64 bytes (0x40) */
FLASH (rx) : ORIGIN = 0x00030040, LENGTH = 0x0005FFC0
- SRAM (rwx) : ORIGIN = 0x20002000, LENGTH = 62K
+ SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K
}
/*
diff --git a/boards/layout_opentitan.ld b/boards/layout_opentitan.ld
index db48eef..0ae4b60 100644
--- a/boards/layout_opentitan.ld
+++ b/boards/layout_opentitan.ld
@@ -10,7 +10,7 @@
* the kernel binary, check for the actual address of APP_MEMORY!
*/
FLASH (rx) : ORIGIN = 0x20030040, LENGTH = 32M
- SRAM (rwx) : ORIGIN = 0x10002800, LENGTH = 512K
+ SRAM (rwx) : ORIGIN = 0x10002D00, LENGTH = 512K
}
/*
diff --git a/core/examples/empty_main.rs b/core/examples/empty_main.rs
new file mode 100644
index 0000000..dd062bc
--- /dev/null
+++ b/core/examples/empty_main.rs
@@ -0,0 +1,14 @@
+// The most minimal libtock-core example possible. This file primarily exists
+// for code size measurement, as this should create the smallest-possible
+// libtock-core app.
+
+#![no_std]
+
+// If you don't *use* anything from libtock-core directly, cargo will not link
+// it into the executable. However, we still need the runtime and lang items.
+// Therefore a libtock-core app that doesn't directly mention anything in
+// libtock-core needs to explicitly declare its dependency on libtock-core as
+// follows.
+extern crate libtock_core;
+
+fn main() {}
diff --git a/doc/Dependencies.md b/doc/Dependencies.md
new file mode 100644
index 0000000..f157049
--- /dev/null
+++ b/doc/Dependencies.md
@@ -0,0 +1,29 @@
+Third Party Dependencies
+========================
+
+This document is about dependencies that are required to build applications
+using `libtock-rs`. These dependencies are not contained in the libtock-rs
+repository, but are used by libtock-rs when libtock-rs is used as a dependency
+of an application. Dependencies required to run `libtock-rs`' tests (such as
+`make`) are outside the scope of this document.
+
+## Unaudited Required Dependencies
+
+`libtock-rs` has the following required build dependencies, none of which are
+currently audited:
+
+* The Rust toolchain, including
+ [`cargo`](https://github.com/rust-lang/cargo),
+ [`rustc`](https://github.com/rust-lang/rust/tree/master/src/rustc), and
+ [`libcore`](https://github.com/rust-lang/rust/tree/master/src/libcore). The
+ specific toolchain version used is specified by the `rust-toolchain` file at
+ the root of the repository.
+* [`syn`](https://crates.io/crates/syn), pulled in by `libtock_codegen`.
+* [`quote`](https://crates.io/crates/quote), pulled in by `libtock_codegen`.
+* [`proc-macro2`](https://crates.io/crates/proc-macro2), pulled in by
+ `libtock_codegen`.
+
+## Avoiding Optional Dependencies
+
+To avoid pulling in optional dependencies, users should use `libtock-core`
+instead of `libtock`. `libtock-core` is in the `core/` directory.
diff --git a/examples-features/libtock_test.rs b/examples-features/libtock_test.rs
index 5fe9e59..9a64e67 100644
--- a/examples-features/libtock_test.rs
+++ b/examples-features/libtock_test.rs
@@ -1,5 +1,6 @@
// Libtock regression tests to be used with real hardware.
-// Requires P0.03 and P0.04 to be connected (on a nRF52 DK).
+// Requires P0.03 and P0.04 to be connected (on a nRF52 DK) and
+// P0.01 and P0.03 to be connected (on a nRF52840dk).
#![no_std]
extern crate alloc;
diff --git a/test-runner/src/main.rs b/test-runner/src/main.rs
index 99b941c..e297e8e 100644
--- a/test-runner/src/main.rs
+++ b/test-runner/src/main.rs
@@ -14,14 +14,15 @@
async fn perform_tests() -> Result<(), Box<dyn std::error::Error>> {
let mut failed_tests = Vec::new();
- let tests = Command::new("qemu-system-riscv32")
+ let tests = Command::new("tock/tools/qemu/riscv32-softmmu/qemu-system-riscv32")
.arg("-M")
.arg("sifive_e,revb=true")
.arg("-kernel")
- .arg("../../tock/target/riscv32imac-unknown-none-elf/release/hifive1")
+ .arg("tock/target/riscv32imac-unknown-none-elf/release/hifive1")
.arg("-device")
- .arg("loader,file=./../target/riscv32imac-unknown-none-elf/tab/hifive1/libtock_test/rv32imac.tbf,addr=0x20040000")
+ .arg("loader,file=target/riscv32imac-unknown-none-elf/tab/hifive1/libtock_test/rv32imac.tbf,addr=0x20040000")
.arg("-nographic")
+ .stdin(Stdio::null())
.stdout(Stdio::piped())
.kill_on_drop(true)
.spawn()?;
diff --git a/tock b/tock
new file mode 160000
index 0000000..152189f
--- /dev/null
+++ b/tock
@@ -0,0 +1 @@
+Subproject commit 152189fe077aea955332ee3c28ccbee519d8b072
diff --git a/tools/flash.sh b/tools/flash.sh
index f24127e..ea75dee 100755
--- a/tools/flash.sh
+++ b/tools/flash.sh
@@ -3,7 +3,7 @@
set -eux
artifact="$(basename $1)"
-rust_target_folder="$(readlink -f $(dirname $1)/../..)"
+rust_target_folder="$(cd $(dirname $1)/../.. && pwd -P)"
if [ -z $APP_HEAP_SIZE ]; then
echo "Set APP_HEAP_SIZE to a value"
exit 1
diff --git a/tools/print-sizes/Cargo.toml b/tools/print-sizes/Cargo.toml
new file mode 100644
index 0000000..97bdc48
--- /dev/null
+++ b/tools/print-sizes/Cargo.toml
@@ -0,0 +1,13 @@
+# Finds all the libtock-core and libtock-rs examples and prints the sizes of
+# several of their sections. Searches the target/$ARCH/release directory. Note
+# that print-sizes will not build the examples; that is done by the
+# `print-sizes` Makefile action.
+
+[package]
+authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
+edition = "2018"
+name = "print-sizes"
+version = "0.1.0"
+
+[dependencies]
+elf = "0.0.10"
diff --git a/tools/print-sizes/src/main.rs b/tools/print-sizes/src/main.rs
new file mode 100644
index 0000000..dcd7777
--- /dev/null
+++ b/tools/print-sizes/src/main.rs
@@ -0,0 +1,142 @@
+// Architectures that we expect the examples to be built for.
+const ARCHITECTURES: [&str; 2] = ["riscv32imc-unknown-none-elf", "thumbv7em-none-eabi"];
+
+// The order of these fields actually matters, because it affects the derived
+// Ord impl. I have a suspicion that when I introduce size diffs into the CI,
+// this order will make the eventual diffs easier to understand than other
+// orderings.
+#[derive(Eq, PartialEq, PartialOrd, Ord)]
+struct Example {
+ name: String,
+ arch: &'static str,
+ path: std::path::PathBuf,
+}
+
+// Finds the example binaries and returns a list of their paths.
+fn find_examples() -> Vec<Example> {
+ // Find target/ using std::env::current_exe().
+ let exe_dir = std::env::current_exe().expect("Unable to find executable location");
+ let target_dir = exe_dir
+ .parent()
+ .expect("Unable to find target/ directory")
+ .parent()
+ .expect("Unable to find target/ directory");
+
+ let mut examples = Vec::new();
+
+ for arch in &ARCHITECTURES {
+ // Set examples_dir to target/$ARCH/examples/
+ let mut examples_dir = target_dir.to_path_buf();
+ examples_dir.push(arch);
+ examples_dir.push("release");
+ examples_dir.push("examples");
+
+ // If the architecture's examples directory exists, iterate through the
+ // files through it and search for examples. If the directory doesn't
+ // exist we skip this architecture.
+ if let Ok(read_dir) = examples_dir.read_dir() {
+ for file in read_dir.filter_map(Result::ok) {
+ use std::os::unix::ffi::OsStrExt;
+
+ // Skip entries that are not files. If file_type() returns
+ // Err(_) we skip the entry as well.
+ if !file.file_type().map_or(false, |t| t.is_file()) {
+ continue;
+ }
+
+ // Skip files with dots (*.d files) and hyphens (-$HASH) in
+ // them.
+ if file.file_name().as_bytes().contains(&b'.')
+ || file.file_name().as_bytes().contains(&b'-')
+ {
+ continue;
+ }
+
+ examples.push(Example {
+ name: file.file_name().to_string_lossy().into_owned(),
+ arch,
+ path: file.path(),
+ });
+ }
+ }
+ }
+
+ examples
+}
+
+struct ElfSizes {
+ bss: u64,
+ data: u64,
+ rodata: u64,
+ text: u64,
+}
+
+fn get_sizes(path: &std::path::Path) -> ElfSizes {
+ let file = elf::File::open_path(path).expect("Unable to open example binary");
+ let mut sizes = ElfSizes {
+ bss: 0,
+ data: 0,
+ rodata: 0,
+ text: 0,
+ };
+ for section in file.sections {
+ match section.shdr.name.as_ref() {
+ ".bss" => sizes.bss = section.shdr.size,
+ ".data" => sizes.data = section.shdr.size,
+ ".rodata" => sizes.rodata = section.shdr.size,
+ ".text" => sizes.text = section.shdr.size,
+ _ => {}
+ }
+ }
+ sizes
+}
+
+struct ExampleData {
+ name: String,
+ arch: &'static str,
+ sizes: ElfSizes,
+}
+
+fn main() {
+ let mut examples = find_examples();
+ examples.sort_unstable();
+ let example_data: Vec<_> = examples
+ .drain(..)
+ .map(|example| ExampleData {
+ name: example.name,
+ arch: example.arch,
+ sizes: get_sizes(&example.path),
+ })
+ .collect();
+
+ let name_width = 20;
+ let arch_width = example_data
+ .iter()
+ .map(|a| a.arch.len())
+ .max()
+ .expect("No examples found");
+ let section_width = 7;
+
+ // TODO: We do not currently print out .rodata's size. Currently, the linker
+ // script embeds .rodata in .text, so we don't see it as a separate section
+ // here. We should modify the linker script to put .rodata in its own
+ // section. Until that is done, .rodata's size will be counted as part of
+ // .text, so we'll just print .text's size for now.
+ println!(
+ "{0:1$} {2:3$} {4:>7$} {5:>7$} {6:>7$}",
+ "Example", name_width, "Architecture", arch_width, ".bss", ".data", ".text", section_width
+ );
+ for data in example_data {
+ println!(
+ "{0:1$} {2:3$} {4:7$} {5:7$} {6:7$}",
+ data.name,
+ name_width,
+ data.arch,
+ arch_width,
+ data.sizes.bss,
+ data.sizes.data,
+ data.sizes.text,
+ section_width
+ );
+ }
+}