Add code for tutorial 02

pull/35/head
Andre Richter 5 years ago
parent cb78e1c7cc
commit d6accd6c69
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,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,88 +0,0 @@
# Tutorial 02 - Multicore Rust
Now let's try something more complex, shall we? By complex I mean stopping the
CPU cores just like in the first tutorial, but this time stop one of them from
**Rust**!
## Boot code
In order to conveniently incorporate Rust code, we are restructuring our crate a
bit.
We reuse a lot of steps that are explained in great detail in [The
Embedonomicon][nom], so please take your time and read up on it. Afterwards, you
can compare to the files in this crate and see what we actually kept to get our
Raspberry Pi 3 tutorial going. Here's a short summary of the new structure of
the crate:
- `raspi3_boot/`: The extern crate containing boot code as presented in the
Embedonomicon.
- In a small deviation to the Embedonomicon, `lib.rs` also includes
`boot_cores.S` from the previous tutorial, still with the
[global_asm!][gasm] macro.
- Therefore, `boot_cores.S` has been moved into `raspi3_boot/src/`.
- `src`: Source code of our actual Rust code, currently only containing
`main.rs` executing an endless loop.
[nom]: https://rust-embedded.github.io/embedonomicon/
[gasm]: https://doc.rust-lang.org/unstable-book/language-features/global-asm.html
### Changes to `boot_cores.S`
In contrast to the previous tutorial, we are now [distinguishing the
cores][dist]. To do so, we read the [mpidr_el1][mpdir] system register. If it is
not zero, we enter the former infinite waiting loop, aka stopping the respective
CPU core.
If the result of the read from `mpidr_el1` is zero, which means we are executing
on core0, we set up the stack for that core, and afterwards call the Rust
`reset()` function of the boot code in `raspi3_boot/src/lib.rs`. In case the
Rust code returns (which it never should), we also jump to the same infinite
loop the other CPU cores are running.
The Rust `reset()`, in turn, will then zero-out the `bss section` (the next
section explains what that is) and finally call our `main()` function from
`main.rs`.
[dist]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/CFHCIDCH.html
[mpdir]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500g/BABHBJCI.html
## Changes to `link.ld`
Since we are using a high-level language now in the form of Rust, we also take
precautions to have eventual space reserved in memory for the [bss
segment][bss], which is needed in case zero-initialized static variables are
allocated in the Rust code.
[bss]: https://en.wikipedia.org/wiki/.bss
Therefore, we added the `bss` segment to the linker script and export its
properties via `__bss_start` and `__bss_size`, which will be picked up and
zeroed out by the boot code in `raspi3_boot/src/lib.rs`.
Additionally, there is a [data segment][data] now.
[data]: https://en.wikipedia.org/wiki/Data_segment
Finally, we need to take care that we still start the text segment with the
assembly code and not the newly added Rust code. This is taken care of by
placing the `.text.boot` section before all other new text sections
`KEEP(*(.text.boot)) *(.text .text.* ...`.
This way, the assembly stays at the `0x80_000` address, which is the entry point
of the RPi3 CPU.
## Changes to `Makefile`
We've added one more target:
- [clippy] is Rust's linter, and can give you useful advise to improve your
code. Invoke with `make clippy`.
[clippy]: https://github.com/rust-lang-nursery/rust-clippy
From now on, we can use the same Makefile for every tutorial, regardless of the
number of Rust sources, and we won't discuss it any further.
## main.rs
Finally, our first Rust code. Just an empty loop, but still! :-)

Binary file not shown.

@ -1,55 +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.*)
}
.rodata :
{
*(.rodata .rodata.*)
}
.data :
{
*(.data .data.*)
}
.bss ALIGN(8):
{
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}

@ -1,9 +0,0 @@
[package]
name = "raspi3_boot"
version = "0.1.0"
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2018"
[dependencies]
panic-abort = "0.3.1"
r0 = "0.2.2"

@ -1,48 +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:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_boot_cores
mov sp, x1
// jump to Rust code, should not return
bl reset
// for failsafe, halt this core too
b 1b

@ -1,79 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2018 Jorge Aparicio
* 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.
*/
#![deny(missing_docs)]
#![deny(warnings)]
#![no_std]
#![feature(global_asm)]
//! Low-level boot of the Raspberry's processor
extern crate panic_abort;
/// Type check the user-supplied entry function.
#[macro_export]
macro_rules! entry {
($path:path) => {
/// # Safety
///
/// - User must ensure to provide a suitable main function for the
/// platform.
#[export_name = "main"]
pub unsafe fn __main() -> ! {
// type check the given path
let f: fn() -> ! = $path;
f()
}
};
}
/// Reset function.
///
/// Initializes the bss section before calling into the user's `main()`.
///
/// # Safety
///
/// - Only a single core must be active and running this function.
#[no_mangle]
pub unsafe extern "C" fn reset() -> ! {
extern "C" {
// Boundaries of the .bss section, provided by the linker script
static mut __bss_start: u64;
static mut __bss_end: u64;
}
// Zeroes the .bss section
r0::zero_bss(&mut __bss_start, &mut __bss_end);
extern "Rust" {
fn main() -> !;
}
main();
}
// Disable all cores except core 0, and then jump to reset()
global_asm!(include_str!("boot_cores.S"));

@ -1,32 +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]
fn kernel_entry() -> ! {
loop {}
}
raspi3_boot::entry!(kernel_entry);

@ -1,30 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "kernel8"
name = "kernel"
version = "0.1.0"
dependencies = [
"raspi3_boot 0.1.0",
"r0 0.2.2 (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"
[[package]]
name = "r0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "raspi3_boot"
version = "0.1.0"
dependencies = [
"panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"r0 0.2.2 (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"
"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"

@ -1,11 +1,16 @@
[package]
name = "kernel8"
name = "kernel"
version = "0.1.0"
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
edition = "2018"
[dependencies]
raspi3_boot = { path = "raspi3_boot" }
[package.metadata.cargo-xbuild]
sysroot_path = "../xbuild_sysroot"
# The features section is used to select the target board.
[features]
default = []
bsp_rpi3 = []
[dependencies]
r0 = "0.2.2"

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

Binary file not shown.

@ -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,35 @@
/* 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)
}
.rodata :
{
*(.rodata)
}
.data :
{
*(.data)
}
/* Align to 8 byte boundary */
.bss ALIGN(8):
{
__bss_start = .;
*(.bss);
__bss_end = .;
}
/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,19 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
.global _start
_start:
mrs x1, mpidr_el1 // Read Multiprocessor Affinity Register
and x1, x1, #3 // Clear all bits except [1:0], which hold core id
cbz x1, 2f // Jump to label 2 if we are core 0
1: wfe // Wait for event
b 1b // In case an event happend, jump back to 1
2: // If we are here, we are core0
ldr x1, =_start // Load address of function "_start()"
mov sp, x1 // Set start of stack to before our code, aka first
// address before "_start()"
bl init // Jump to the "init()" kernel function
b 1b // We should never reach here. But just in case,
// park this core aswell

@ -0,0 +1,23 @@
// 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;
// Afterwards, `BSP`'s early init code calls `runtime_init::init()` of this
// module, which on completion, jumps to `kernel_entry()`.
mod runtime_init;
/// Entrypoint of the `kernel`.
fn kernel_entry() -> ! {
panic!()
}

@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2018-2019 Andre Richter <andre.o.richter@gmail.com>
//! Rust runtime initialization code.
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section,
/// then calls the kernel entry.
///
/// Called from BSP code.
///
/// # Safety
///
/// - Only a single core must be active and running this function.
#[no_mangle]
pub unsafe extern "C" fn init() -> ! {
extern "C" {
// Boundaries of the .bss section, provided by the linker script
static mut __bss_start: u64;
static mut __bss_end: u64;
}
// Zero out the .bss section
r0::zero_bss(&mut __bss_start, &mut __bss_end);
crate::kernel_entry()
}
Loading…
Cancel
Save