From cb78e1c7cc61f002b6972487ca5804e06992ba4c Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Sun, 22 Sep 2019 00:32:54 +0200 Subject: [PATCH] Add code for tutorial 01 --- .01_bareminimum/.cargo/config | 5 - .01_bareminimum/Cargo.lock | 16 --- .01_bareminimum/Makefile | 68 ---------- .01_bareminimum/README.md | 117 ------------------ .01_bareminimum/link.ld | 37 ------ .01_bareminimum/src/boot_cores.S | 33 ----- .01_bareminimum/src/main.rs | 31 ----- 01_wait_forever/Cargo.lock | 6 + .../Cargo.toml | 13 +- 01_wait_forever/Makefile | 76 ++++++++++++ .../kernel8 => 01_wait_forever/kernel | Bin 66040 -> 66080 bytes .../kernel8.img | 0 01_wait_forever/src/bsp.rs | 11 ++ 01_wait_forever/src/bsp/rpi3.rs | 9 ++ 01_wait_forever/src/bsp/rpi3/link.ld | 17 +++ 01_wait_forever/src/bsp/rpi3/panic_wait.rs | 16 +++ 01_wait_forever/src/bsp/rpi3/start.S | 9 ++ 01_wait_forever/src/main.rs | 16 +++ 18 files changed, 169 insertions(+), 311 deletions(-) delete mode 100644 .01_bareminimum/.cargo/config delete mode 100644 .01_bareminimum/Cargo.lock delete mode 100644 .01_bareminimum/Makefile delete mode 100644 .01_bareminimum/README.md delete mode 100644 .01_bareminimum/link.ld delete mode 100644 .01_bareminimum/src/boot_cores.S delete mode 100644 .01_bareminimum/src/main.rs create mode 100644 01_wait_forever/Cargo.lock rename {.01_bareminimum => 01_wait_forever}/Cargo.toml (61%) create mode 100644 01_wait_forever/Makefile rename .01_bareminimum/kernel8 => 01_wait_forever/kernel (99%) rename {.01_bareminimum => 01_wait_forever}/kernel8.img (100%) create mode 100644 01_wait_forever/src/bsp.rs create mode 100644 01_wait_forever/src/bsp/rpi3.rs create mode 100644 01_wait_forever/src/bsp/rpi3/link.ld create mode 100644 01_wait_forever/src/bsp/rpi3/panic_wait.rs create mode 100644 01_wait_forever/src/bsp/rpi3/start.S create mode 100644 01_wait_forever/src/main.rs diff --git a/.01_bareminimum/.cargo/config b/.01_bareminimum/.cargo/config deleted file mode 100644 index de3f84c9..00000000 --- a/.01_bareminimum/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] diff --git a/.01_bareminimum/Cargo.lock b/.01_bareminimum/Cargo.lock deleted file mode 100644 index b06d8dbc..00000000 --- a/.01_bareminimum/Cargo.lock +++ /dev/null @@ -1,16 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "kernel8" -version = "0.1.0" -dependencies = [ - "panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "panic-abort" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" diff --git a/.01_bareminimum/Makefile b/.01_bareminimum/Makefile deleted file mode 100644 index e98a5947..00000000 --- a/.01_bareminimum/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# MIT License -# -# Copyright (c) 2018-2019 Andre Richter -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -TARGET = aarch64-unknown-none-softfloat - -SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) link.ld - - -XRUSTC_CMD = cargo xrustc --target=$(TARGET) --release -CARGO_OUTPUT = target/$(TARGET)/release/kernel8 - -OBJCOPY = cargo objcopy -- -OBJCOPY_PARAMS = --strip-all -O binary - -CONTAINER_UTILS = andrerichter/raspi3-utils - -DOCKER_CMD = docker run -it --rm -DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work - -DOCKER_EXEC_QEMU = qemu-system-aarch64 -M raspi3 -kernel kernel8.img - -.PHONY: all qemu clippy clean objdump nm - -all: clean kernel8.img - -$(CARGO_OUTPUT): $(SOURCES) - $(XRUSTC_CMD) - -kernel8.img: $(CARGO_OUTPUT) - cp $< . - $(OBJCOPY) $(OBJCOPY_PARAMS) $< kernel8.img - -qemu: all - $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ - $(DOCKER_EXEC_QEMU) -d in_asm - -clippy: - cargo xclippy --target=$(TARGET) - -clean: - cargo clean - -objdump: - cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel8 - -nm: - cargo nm --target $(TARGET) -- kernel8 | sort diff --git a/.01_bareminimum/README.md b/.01_bareminimum/README.md deleted file mode 100644 index cc5237ad..00000000 --- a/.01_bareminimum/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# Tutorial 01 - Bare Minimum - -Okay, we're not going to do much here, just test our toolchain. The resulting -kernel8.img should boot on the Raspberry Pi 3, and stop all CPU cores in an -infinite waiting loop. You can check that by running - -```console -ferris@box:~$ make qemu -... some output removed for clearity: ... ----------------- -IN: -0x00080000: d503205f wfe -0x00080004: 17ffffff b #0x80000 -``` - -## Crate setup - -In this tutorial, we are compiling a kernel that is in the end only executing a -single assembly instruction which we program with an assembly file. - -However, since we want to use the toolchain that is delivered with `rustup` as -much as possible, we are already setting up a Rust crate. This allows us to use -`rustc` and LLVM's `lld.ld` linker to process our assembly file. - -## Target - -The Raspberry Pi 3 features a processor that uses ARM's `AArch64` architecture. -Conveniently, Rust already provides a generic target for bare-metal aarch64 code -that we can leverage. It is called [aarch64-unknown-none-softfloat]. - -[aarch64-unknown-none-softfloat]: https://github.com/rust-lang/rust/blob/master/src/librustc_target/spec/aarch64_unknown_none_softfloat.rs - -In the `Makefile`, we select this target in various places by passing it to -cargo using the `--target` cmdline argument. - -Additionally, we provide a config file in `.cargo/config` were we make further -specializations: - -```toml -[target.aarch64-unknown-none-softfloat] -rustflags = [ - "-C", "link-arg=-Tlink.ld", - "-C", "target-cpu=cortex-a53", -] -``` - -The first line tells rustc to use our custom `link.ld` linker script. The -second argument specifies the exact CPU type that is used on Raspberry Pi 3, so -that the compiler can optimize for it. - -The target itself tells the compiler already to not use floating point -operations, which is hinted by the `-softfloat` appendix. This is a common -choice when writing an operating system kernel. If floating point is not -explicitly disabled, it is possible that the compiler uses auto-vectorization to -optimize, for example, operations on array data structures. This would -implicitly result in use of floating point registers and operations. However, -since it is very costly to save and restore floating point registers during -context-switches, use of fp is usually disabled from the get go to save the -cycles and optimize the kernel for fast context switching. - -Since the `aarch64-unknown-none-softfloat` target is not shipped with an associated -precompiled standard library, and since we anyways modify the target via the -`.cargo/config` file, we are using [cargo-xbuild][xbuild] to compile our own -standard library. This way, we can ensure that our bare-metal code is optimized -throughout. - -[xbuild]: https://github.com/rust-osdev/cargo-xbuild - -## Linker script `link.ld` - -We just set the base address where our kernel8.img will be loaded, and we put -the only section we have there, which is `.text.boot`. Important note, for -AArch64 the load address is **0x80_000**, and not **0x80_00** as with AArch32. - -## Makefile - -Our Makefile has a few useful targets: -- `kernel8` compiles the crate either in release or debug mode. For the latter, - add `DEBUG=1` before invoking make, e.g. `DEBUG=1 make` -- `kernel8.img` uses `cargo objcopy` to generate our kernel binary. Citing the [binutils documentation][butils]: - - "_When objcopy generates a raw binary file, it will essentially produce a - memory dump of the contents of the input object file. All symbols and - relocation information will be discarded. The memory dump will start at - the load address of the lowest section copied into the output file._" -- `qemu` loads our kernel into an emulated RPi3, and shows as output the - assembler blocks that are executed. This happens in a docker container. - -[butils]: https://sourceware.org/binutils/docs/binutils/objcopy.html - -## main.rs - -We define the crate to not use the standard library (`#![no_std]`), indicate -that it does not have a main function via `#![no_main]`, and also define a stub -for the `panic_fmt()` handler, which is a requirement for `no_std` crates. We do -this by pulling in the [panic-abort][pa] crate. - -[pa]: https://crates.io/crates/panic-abort - -In summary, we (mis)use `main.rs` as a wrapper to process our assembly file via -`rustc`. The assembly file iself is included with the [global_asm!()][gasm] -macro. - -[gasm]: https://doc.rust-lang.org/unstable-book/language-features/global-asm.html - -## boot_cores.S - -When the control is passed to kernel8.img, the environment is not ready yet for -Rust. Therefore we must implement a small preamble in assembly, no Rust for now. - -All we do is executing [wfe][wfe], an instruction that puts the CPU cores to -sleep until an asynchronous event occurs. If that happens, we jump right back to -`wfe` again. - -[wfe]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360e/CHDBGCFH.html - -Note that the CPU has 4 cores. All of them will execute the same infinite loop -for now. diff --git a/.01_bareminimum/link.ld b/.01_bareminimum/link.ld deleted file mode 100644 index 13de9dc4..00000000 --- a/.01_bareminimum/link.ld +++ /dev/null @@ -1,37 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -ENTRY(_boot_cores); - -SECTIONS -{ - . = 0x80000; - - .text : - { - KEEP(*(.text.boot)) *(.text .text.*) - } - - /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } -} diff --git a/.01_bareminimum/src/boot_cores.S b/.01_bareminimum/src/boot_cores.S deleted file mode 100644 index 15a1431d..00000000 --- a/.01_bareminimum/src/boot_cores.S +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -.section ".text.boot" - -.global _boot_cores - -_boot_cores: -1: wfe - b 1b diff --git a/.01_bareminimum/src/main.rs b/.01_bareminimum/src/main.rs deleted file mode 100644 index 6a5e45dc..00000000 --- a/.01_bareminimum/src/main.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 Andre Richter - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#![no_std] -#![no_main] -#![feature(global_asm)] - -extern crate panic_abort; - -global_asm!(include_str!("boot_cores.S")); diff --git a/01_wait_forever/Cargo.lock b/01_wait_forever/Cargo.lock new file mode 100644 index 00000000..3e9c3111 --- /dev/null +++ b/01_wait_forever/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "kernel" +version = "0.1.0" + diff --git a/.01_bareminimum/Cargo.toml b/01_wait_forever/Cargo.toml similarity index 61% rename from .01_bareminimum/Cargo.toml rename to 01_wait_forever/Cargo.toml index 26996a7f..c0949451 100644 --- a/.01_bareminimum/Cargo.toml +++ b/01_wait_forever/Cargo.toml @@ -1,11 +1,16 @@ [package] -name = "kernel8" +name = "kernel" version = "0.1.0" authors = ["Andre Richter "] edition = "2018" -[dependencies] -panic-abort = "0.3.1" - [package.metadata.cargo-xbuild] sysroot_path = "../xbuild_sysroot" + +# The features section is used to select the target board. +[features] +default = [] +bsp_rpi3 = [] + +[dependencies] + diff --git a/01_wait_forever/Makefile b/01_wait_forever/Makefile new file mode 100644 index 00000000..8ef00caa --- /dev/null +++ b/01_wait_forever/Makefile @@ -0,0 +1,76 @@ +## SPDX-License-Identifier: MIT +## +## Copyright (c) 2018-2019 Andre Richter + +# Default to the RPi3 +ifndef BSP + BSP = bsp_rpi3 +endif + +# BSP-specific arguments +ifeq ($(BSP),bsp_rpi3) + TARGET = aarch64-unknown-none + OUTPUT = kernel8.img + QEMU_BINARY = qemu-system-aarch64 + QEMU_MACHINE_TYPE = raspi3 + QEMU_MISC_ARGS = -d in_asm + LINKER_FILE = src/bsp/rpi3/link.ld + RUSTC_MISC_ARGS = -C target-feature=-fp-armv8 -C target-cpu=cortex-a53 +endif + +SOURCES = $(wildcard **/*.rs) $(wildcard **/*.S) $(wildcard **/*.ld) + +XRUSTC_CMD = cargo xrustc \ + --target=$(TARGET) \ + --features $(BSP) \ + --release \ + -- \ + -C link-arg=-T$(LINKER_FILE) \ + $(RUSTC_MISC_ARGS) + +CARGO_OUTPUT = target/$(TARGET)/release/kernel + +OBJCOPY_CMD = cargo objcopy \ + -- \ + --strip-all \ + -O binary + +CONTAINER_UTILS = rustembedded/osdev-utils + +DOCKER_CMD = docker run -it --rm +DOCKER_ARG_CURDIR = -v $(shell pwd):/work -w /work +DOCKER_EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE) -kernel $(OUTPUT) + +.PHONY: all qemu clippy clean readelf objdump nm + +all: clean $(OUTPUT) + +$(CARGO_OUTPUT): $(SOURCES) + RUSTFLAGS="-D warnings -D missing_docs" $(XRUSTC_CMD) + +$(OUTPUT): $(CARGO_OUTPUT) + cp $< . + $(OBJCOPY_CMD) $< $(OUTPUT) + +doc: + cargo xdoc --target=$(TARGET) --features $(BSP) --document-private-items + xdg-open target/$(TARGET)/doc/kernel/index.html + +qemu: all + $(DOCKER_CMD) $(DOCKER_ARG_CURDIR) $(CONTAINER_UTILS) \ + $(DOCKER_EXEC_QEMU) $(QEMU_MISC_ARGS) + +clippy: + cargo xclippy --target=$(TARGET) --features $(BSP) + +clean: + cargo clean + +readelf: + readelf -a kernel + +objdump: + cargo objdump --target $(TARGET) -- -disassemble -print-imm-hex kernel + +nm: + cargo nm --target $(TARGET) -- kernel | sort diff --git a/.01_bareminimum/kernel8 b/01_wait_forever/kernel similarity index 99% rename from .01_bareminimum/kernel8 rename to 01_wait_forever/kernel index 6464a210ae7d661cc75568d88571f9a84e037d30..d96e0122a90ed12c316110476336ffba7a573f03 100755 GIT binary patch delta 158 zcmey-%(9?`Wr7CdgGSA%nvDF6;!_nF#U*taK!6d5IlwF!VKg<6(cVzcGB-UrE44U7 zH#xmj&wwF2wJ0w&2UXONL8SsH6<=JESX44~BV#!u%XCdfMt$B2s97vPnq_(_BcnEB b!}N)ajP{%h!4@(wSWXpW6rQfb$jAc#=YJt* delta 121 zcmZ3`!t$e;Wr7Cdjz-O?nvDF65>o>i#TjL%W-{6 + +//! Conditional exporting of Board Support Packages. + +#[cfg(feature = "bsp_rpi3")] +pub mod rpi3; + +#[cfg(feature = "bsp_rpi3")] +pub use rpi3::*; diff --git a/01_wait_forever/src/bsp/rpi3.rs b/01_wait_forever/src/bsp/rpi3.rs new file mode 100644 index 00000000..3dc8220d --- /dev/null +++ b/01_wait_forever/src/bsp/rpi3.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter + +//! Board Support Package for the Raspberry Pi 3. + +mod panic_wait; + +global_asm!(include_str!("rpi3/start.S")); diff --git a/01_wait_forever/src/bsp/rpi3/link.ld b/01_wait_forever/src/bsp/rpi3/link.ld new file mode 100644 index 00000000..d116d3e2 --- /dev/null +++ b/01_wait_forever/src/bsp/rpi3/link.ld @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2018-2019 Andre Richter + */ + +SECTIONS +{ + /* Set current address to the value from which the RPi3 starts execution */ + . = 0x80000; + + .text : + { + *(.text) + } + + /DISCARD/ : { *(.comment) } +} diff --git a/01_wait_forever/src/bsp/rpi3/panic_wait.rs b/01_wait_forever/src/bsp/rpi3/panic_wait.rs new file mode 100644 index 00000000..328b50f4 --- /dev/null +++ b/01_wait_forever/src/bsp/rpi3/panic_wait.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter + +//! A panic handler that infinitely waits. + +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + unsafe { + loop { + asm!("wfe" :::: "volatile") + } + } +} diff --git a/01_wait_forever/src/bsp/rpi3/start.S b/01_wait_forever/src/bsp/rpi3/start.S new file mode 100644 index 00000000..3d93381e --- /dev/null +++ b/01_wait_forever/src/bsp/rpi3/start.S @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter + +.global _start + +_start: +1: wfe // Wait for event + b 1b // In case an event happend, jump back to 1 diff --git a/01_wait_forever/src/main.rs b/01_wait_forever/src/main.rs new file mode 100644 index 00000000..3753fb2b --- /dev/null +++ b/01_wait_forever/src/main.rs @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// +// Copyright (c) 2018-2019 Andre Richter + +//! The `kernel` + +#![feature(asm)] +#![feature(global_asm)] +#![no_main] +#![no_std] + +// This module conditionally includes the correct `BSP` which provides the +// `_start()` function, the first function to run. +mod bsp; + +// Kernel code coming next tutorial.