Add code for tutorial 01

pull/35/head
Andre Richter 5 years ago
parent fed22475d1
commit cb78e1c7cc
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -1,5 +0,0 @@
[target.aarch64-unknown-none-softfloat]
rustflags = [
"-C", "link-arg=-Tlink.ld",
"-C", "target-cpu=cortex-a53",
]

@ -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"

@ -1,68 +0,0 @@
#
# MIT License
#
# Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
#
# 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

@ -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.

@ -1,37 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2018 Andre Richter <andre.o.richter@gmail.com>
*
* 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*) }
}

@ -1,33 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
* Copyright (c) 2018 Andre Richter <andre.o.richter@gmail.com>
*
* 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

@ -1,31 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2018 Andre Richter <andre.o.richter@gmail.com>
*
* 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"));

@ -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"

@ -1,11 +1,16 @@
[package]
name = "kernel8"
name = "kernel"
version = "0.1.0"
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
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]

@ -0,0 +1,76 @@
## SPDX-License-Identifier: MIT
##
## Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
# 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

@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
//! Conditional exporting of Board Support Packages.
#[cfg(feature = "bsp_rpi3")]
pub mod rpi3;
#[cfg(feature = "bsp_rpi3")]
pub use rpi3::*;

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
//! Board Support Package for the Raspberry Pi 3.
mod panic_wait;
global_asm!(include_str!("rpi3/start.S"));

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
*/
SECTIONS
{
/* Set current address to the value from which the RPi3 starts execution */
. = 0x80000;
.text :
{
*(.text)
}
/DISCARD/ : { *(.comment) }
}

@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
//! A panic handler that infinitely waits.
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
unsafe {
loop {
asm!("wfe" :::: "volatile")
}
}
}

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
.global _start
_start:
1: wfe // Wait for event
b 1b // In case an event happend, jump back to 1

@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
//! 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.
Loading…
Cancel
Save