Revert to assembly boot code
It is too risky to rely on the compiler to not insert any operations using the stack. Having a stack-setting call in Rust using the cortex-a crate as the first action in a Rust-only _start() function does not work if you're subsequently using the stack, because the compiler often inserts the operations to make room on the stack to prepare a function call BEFORE the call to set the stack, which crashes the boot process. Hence, keep on using a small piece of assembly boot code throughout.pull/110/head
parent
6a9af3c202
commit
2432c0d283
@ -1,11 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
.section ".text._start"
|
|
||||||
|
|
||||||
.global _start
|
|
||||||
|
|
||||||
_start:
|
|
||||||
1: wfe // Wait for event
|
|
||||||
b 1b // In case an event happened, jump back to 1
|
|
@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,6 +1,34 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-a"
|
||||||
|
version = "5.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecefc30975eb87afc5a810d4b2305c0ec29e607ea97e51b2ecd80766e9268d28"
|
||||||
|
dependencies = [
|
||||||
|
"register",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-a",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "register"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4a247de29ab7cc8f5006cfe775c4a81c704f9914c5e2a79696862e643135433"
|
||||||
|
dependencies = [
|
||||||
|
"tock-registers",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tock-registers"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f521a79accce68c417c9c77ce22108056b626126da1932f7e2e9b5bbffee0cea"
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
.section ".text._start"
|
|
||||||
|
|
||||||
.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 happened, 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 runtime_init // Jump to the "runtime_init()" kernel function
|
|
||||||
b 1b // We should never reach here. But just in case,
|
|
||||||
// park this core aswell
|
|
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ _core_id_mask, 0b11
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Only proceed on the boot core. Park it otherwise.
|
||||||
|
mrs x1, MPIDR_EL1
|
||||||
|
and x1, x1, _core_id_mask
|
||||||
|
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
|
||||||
|
cmp x1, x2
|
||||||
|
b.ne 1f
|
||||||
|
|
||||||
|
// If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
|
||||||
|
|
||||||
|
// Set the stack pointer.
|
||||||
|
ldr x0, =__boot_core_stack_end_exclusive
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
// Jump to Rust code.
|
||||||
|
b _start_rust
|
||||||
|
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,6 +1,34 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cortex-a"
|
||||||
|
version = "5.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecefc30975eb87afc5a810d4b2305c0ec29e607ea97e51b2ecd80766e9268d28"
|
||||||
|
dependencies = [
|
||||||
|
"register",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel"
|
name = "kernel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cortex-a",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "register"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4a247de29ab7cc8f5006cfe775c4a81c704f9914c5e2a79696862e643135433"
|
||||||
|
dependencies = [
|
||||||
|
"tock-registers",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tock-registers"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f521a79accce68c417c9c77ce22108056b626126da1932f7e2e9b5bbffee0cea"
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
.section ".text._start"
|
|
||||||
|
|
||||||
.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 happened, 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 runtime_init // Jump to the "runtime_init()" kernel function
|
|
||||||
b 1b // We should never reach here. But just in case,
|
|
||||||
// park this core aswell
|
|
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ _core_id_mask, 0b11
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Only proceed on the boot core. Park it otherwise.
|
||||||
|
mrs x1, MPIDR_EL1
|
||||||
|
and x1, x1, _core_id_mask
|
||||||
|
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
|
||||||
|
cmp x1, x2
|
||||||
|
b.ne 1f
|
||||||
|
|
||||||
|
// If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
|
||||||
|
|
||||||
|
// Set the stack pointer.
|
||||||
|
ldr x0, =__boot_core_stack_end_exclusive
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
// Jump to Rust code.
|
||||||
|
b _start_rust
|
||||||
|
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.rulers": [100],
|
|
||||||
"rust-analyzer.checkOnSave.overrideCommand": ["make", "check"],
|
|
||||||
"rust-analyzer.cargo.target": "aarch64-unknown-none-softfloat",
|
|
||||||
"rust-analyzer.cargo.features": ["bsp_rpi3"]
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cortex-a"
|
|
||||||
version = "5.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ecefc30975eb87afc5a810d4b2305c0ec29e607ea97e51b2ecd80766e9268d28"
|
|
||||||
dependencies = [
|
|
||||||
"register",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kernel"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"cortex-a",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "register"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f4a247de29ab7cc8f5006cfe775c4a81c704f9914c5e2a79696862e643135433"
|
|
||||||
dependencies = [
|
|
||||||
"tock-registers",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tock-registers"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f521a79accce68c417c9c77ce22108056b626126da1932f7e2e9b5bbffee0cea"
|
|
@ -1,24 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "kernel"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Andre Richter <andre.o.richter@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
lto = true
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
bsp_rpi3 = []
|
|
||||||
bsp_rpi4 = []
|
|
||||||
|
|
||||||
##--------------------------------------------------------------------------------------------------
|
|
||||||
## Dependencies
|
|
||||||
##--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
|
|
||||||
# Platform specific dependencies
|
|
||||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
|
||||||
cortex-a = { version = "5.x.x" }
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
|||||||
## SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
##
|
|
||||||
## Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
include ../utils/color.mk.in
|
|
||||||
|
|
||||||
# Default to the RPi3
|
|
||||||
BSP ?= rpi3
|
|
||||||
|
|
||||||
# BSP-specific arguments
|
|
||||||
ifeq ($(BSP),rpi3)
|
|
||||||
TARGET = aarch64-unknown-none-softfloat
|
|
||||||
KERNEL_BIN = kernel8.img
|
|
||||||
QEMU_BINARY = qemu-system-aarch64
|
|
||||||
QEMU_MACHINE_TYPE = raspi3
|
|
||||||
QEMU_RELEASE_ARGS = -serial stdio -display none
|
|
||||||
OBJDUMP_BINARY = aarch64-none-elf-objdump
|
|
||||||
NM_BINARY = aarch64-none-elf-nm
|
|
||||||
READELF_BINARY = aarch64-none-elf-readelf
|
|
||||||
LINKER_FILE = src/bsp/raspberrypi/link.ld
|
|
||||||
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53
|
|
||||||
else ifeq ($(BSP),rpi4)
|
|
||||||
TARGET = aarch64-unknown-none-softfloat
|
|
||||||
KERNEL_BIN = kernel8.img
|
|
||||||
QEMU_BINARY = qemu-system-aarch64
|
|
||||||
QEMU_MACHINE_TYPE =
|
|
||||||
QEMU_RELEASE_ARGS = -serial stdio -display none
|
|
||||||
OBJDUMP_BINARY = aarch64-none-elf-objdump
|
|
||||||
NM_BINARY = aarch64-none-elf-nm
|
|
||||||
READELF_BINARY = aarch64-none-elf-readelf
|
|
||||||
LINKER_FILE = src/bsp/raspberrypi/link.ld
|
|
||||||
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Export for build.rs
|
|
||||||
export LINKER_FILE
|
|
||||||
|
|
||||||
QEMU_MISSING_STRING = "This board is not yet supported for QEMU."
|
|
||||||
|
|
||||||
RUSTFLAGS = -C link-arg=-T$(LINKER_FILE) $(RUSTC_MISC_ARGS)
|
|
||||||
RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) -D warnings -D missing_docs
|
|
||||||
|
|
||||||
FEATURES = --features bsp_$(BSP)
|
|
||||||
COMPILER_ARGS = --target=$(TARGET) \
|
|
||||||
$(FEATURES) \
|
|
||||||
--release
|
|
||||||
|
|
||||||
RUSTC_CMD = cargo rustc $(COMPILER_ARGS)
|
|
||||||
DOC_CMD = cargo doc $(COMPILER_ARGS)
|
|
||||||
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
|
|
||||||
CHECK_CMD = cargo check $(COMPILER_ARGS)
|
|
||||||
OBJCOPY_CMD = rust-objcopy \
|
|
||||||
--strip-all \
|
|
||||||
-O binary
|
|
||||||
|
|
||||||
KERNEL_ELF = target/$(TARGET)/release/kernel
|
|
||||||
|
|
||||||
DOCKER_IMAGE = rustembedded/osdev-utils
|
|
||||||
DOCKER_CMD = docker run --rm -v $(shell pwd):/work/tutorial -w /work/tutorial
|
|
||||||
DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i -t
|
|
||||||
|
|
||||||
DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE)
|
|
||||||
DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE)
|
|
||||||
|
|
||||||
EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
|
|
||||||
|
|
||||||
.PHONY: all $(KERNEL_ELF) $(KERNEL_BIN) doc qemu clippy clean readelf objdump nm check
|
|
||||||
|
|
||||||
all: $(KERNEL_BIN)
|
|
||||||
|
|
||||||
$(KERNEL_ELF):
|
|
||||||
$(call colorecho, "\nCompiling kernel - $(BSP)")
|
|
||||||
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD)
|
|
||||||
|
|
||||||
$(KERNEL_BIN): $(KERNEL_ELF)
|
|
||||||
@$(OBJCOPY_CMD) $(KERNEL_ELF) $(KERNEL_BIN)
|
|
||||||
|
|
||||||
doc:
|
|
||||||
$(call colorecho, "\nGenerating docs")
|
|
||||||
@$(DOC_CMD) --document-private-items --open
|
|
||||||
|
|
||||||
ifeq ($(QEMU_MACHINE_TYPE),)
|
|
||||||
qemu:
|
|
||||||
$(call colorecho, "\n$(QEMU_MISSING_STRING)")
|
|
||||||
else
|
|
||||||
qemu: $(KERNEL_BIN)
|
|
||||||
$(call colorecho, "\nLaunching QEMU")
|
|
||||||
@$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
|
|
||||||
endif
|
|
||||||
|
|
||||||
clippy:
|
|
||||||
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf target $(KERNEL_BIN)
|
|
||||||
|
|
||||||
readelf: $(KERNEL_ELF)
|
|
||||||
$(call colorecho, "\nLaunching readelf")
|
|
||||||
@$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF)
|
|
||||||
|
|
||||||
objdump: $(KERNEL_ELF)
|
|
||||||
$(call colorecho, "\nLaunching objdump")
|
|
||||||
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
|
|
||||||
--section .text \
|
|
||||||
--section .rodata \
|
|
||||||
--section .got \
|
|
||||||
$(KERNEL_ELF) | rustfilt
|
|
||||||
|
|
||||||
nm: $(KERNEL_ELF)
|
|
||||||
$(call colorecho, "\nLaunching nm")
|
|
||||||
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
|
|
||||||
|
|
||||||
# For rust-analyzer
|
|
||||||
check:
|
|
||||||
@RUSTFLAGS="$(RUSTFLAGS)" $(CHECK_CMD) --message-format=json
|
|
@ -1,301 +0,0 @@
|
|||||||
# Tutorial 04 - Zero Overhead Abstraction
|
|
||||||
|
|
||||||
## tl;dr
|
|
||||||
|
|
||||||
- All hand-written assembly is replaced by Rust code from the [cortex-a] crate, which provides
|
|
||||||
zero-overhead abstractions and wraps the `unsafe` parts.
|
|
||||||
|
|
||||||
[cortex-a]: https://github.com/rust-embedded/cortex-a
|
|
||||||
|
|
||||||
## Diff to previous
|
|
||||||
```diff
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/Cargo.toml 04_zero_overhead_abstraction/Cargo.toml
|
|
||||||
--- 03_hacky_hello_world/Cargo.toml
|
|
||||||
+++ 04_zero_overhead_abstraction/Cargo.toml
|
|
||||||
@@ -17,3 +17,8 @@
|
|
||||||
##--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
+
|
|
||||||
+# Platform specific dependencies
|
|
||||||
+[target.'cfg(target_arch = "aarch64")'.dependencies]
|
|
||||||
+cortex-a = { version = "5.x.x" }
|
|
||||||
+
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs 04_zero_overhead_abstraction/src/_arch/aarch64/cpu/boot.rs
|
|
||||||
--- 03_hacky_hello_world/src/_arch/aarch64/cpu/boot.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/_arch/aarch64/cpu/boot.rs
|
|
||||||
@@ -11,5 +11,31 @@
|
|
||||||
//!
|
|
||||||
//! crate::cpu::boot::arch_boot
|
|
||||||
|
|
||||||
-// Assembly counterpart to this file. Includes function _start().
|
|
||||||
-global_asm!(include_str!("boot.S"));
|
|
||||||
+use crate::{bsp, cpu};
|
|
||||||
+use cortex_a::regs::*;
|
|
||||||
+
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+// Public Code
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+
|
|
||||||
+/// The entry of the `kernel` binary.
|
|
||||||
+///
|
|
||||||
+/// The function must be named `_start`, because the linker is looking for this exact name.
|
|
||||||
+///
|
|
||||||
+/// # Safety
|
|
||||||
+///
|
|
||||||
+/// - Linker script must ensure to place this function where it is expected by the target machine.
|
|
||||||
+/// - We have to hope that the compiler omits any stack pointer usage before the stack pointer is
|
|
||||||
+/// actually set (`SP.set()`).
|
|
||||||
+#[no_mangle]
|
|
||||||
+pub unsafe fn _start() -> ! {
|
|
||||||
+ use crate::runtime_init;
|
|
||||||
+
|
|
||||||
+ if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
|
|
||||||
+ SP.set(bsp::memory::boot_core_stack_end() as u64);
|
|
||||||
+ runtime_init::runtime_init()
|
|
||||||
+ } else {
|
|
||||||
+ // If not core0, infinitely wait for events.
|
|
||||||
+ cpu::wait_forever()
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/_arch/aarch64/cpu/boot.S 04_zero_overhead_abstraction/src/_arch/aarch64/cpu/boot.S
|
|
||||||
--- 03_hacky_hello_world/src/_arch/aarch64/cpu/boot.S
|
|
||||||
+++ 04_zero_overhead_abstraction/src/_arch/aarch64/cpu/boot.S
|
|
||||||
@@ -1,21 +0,0 @@
|
|
||||||
-// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
-//
|
|
||||||
-// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
-
|
|
||||||
-.section ".text._start"
|
|
||||||
-
|
|
||||||
-.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 happened, 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 runtime_init // Jump to the "runtime_init()" kernel function
|
|
||||||
- b 1b // We should never reach here. But just in case,
|
|
||||||
- // park this core aswell
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/_arch/aarch64/cpu/smp.rs 04_zero_overhead_abstraction/src/_arch/aarch64/cpu/smp.rs
|
|
||||||
--- 03_hacky_hello_world/src/_arch/aarch64/cpu/smp.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/_arch/aarch64/cpu/smp.rs
|
|
||||||
@@ -0,0 +1,29 @@
|
|
||||||
+// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
+//
|
|
||||||
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
+
|
|
||||||
+//! Architectural symmetric multiprocessing.
|
|
||||||
+//!
|
|
||||||
+//! # Orientation
|
|
||||||
+//!
|
|
||||||
+//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
+//! file is:
|
|
||||||
+//!
|
|
||||||
+//! crate::cpu::smp::arch_smp
|
|
||||||
+
|
|
||||||
+use cortex_a::regs::*;
|
|
||||||
+
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+// Public Code
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+
|
|
||||||
+/// Return the executing core's id.
|
|
||||||
+#[inline(always)]
|
|
||||||
+pub fn core_id<T>() -> T
|
|
||||||
+where
|
|
||||||
+ T: From<u8>,
|
|
||||||
+{
|
|
||||||
+ const CORE_MASK: u64 = 0b11;
|
|
||||||
+
|
|
||||||
+ T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
|
||||||
+}
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/_arch/aarch64/cpu.rs 04_zero_overhead_abstraction/src/_arch/aarch64/cpu.rs
|
|
||||||
--- 03_hacky_hello_world/src/_arch/aarch64/cpu.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/_arch/aarch64/cpu.rs
|
|
||||||
@@ -11,6 +11,8 @@
|
|
||||||
//!
|
|
||||||
//! crate::cpu::arch_cpu
|
|
||||||
|
|
||||||
+use cortex_a::asm;
|
|
||||||
+
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
@@ -18,13 +20,7 @@
|
|
||||||
/// Pause execution on the core.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn wait_forever() -> ! {
|
|
||||||
- unsafe {
|
|
||||||
- loop {
|
|
||||||
- #[rustfmt::skip]
|
|
||||||
- asm!(
|
|
||||||
- "wfe",
|
|
||||||
- options(nomem, nostack, preserves_flags)
|
|
||||||
- );
|
|
||||||
- }
|
|
||||||
+ loop {
|
|
||||||
+ asm::wfe()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs 04_zero_overhead_abstraction/src/bsp/raspberrypi/cpu.rs
|
|
||||||
--- 03_hacky_hello_world/src/bsp/raspberrypi/cpu.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/bsp/raspberrypi/cpu.rs
|
|
||||||
@@ -0,0 +1,12 @@
|
|
||||||
+// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
+//
|
|
||||||
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
+
|
|
||||||
+//! BSP Processor code.
|
|
||||||
+
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+// Public Definitions
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+
|
|
||||||
+/// Used by `arch` code to find the early boot core.
|
|
||||||
+pub const BOOT_CORE_ID: u64 = 0;
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/link.ld 04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld
|
|
||||||
--- 03_hacky_hello_world/src/bsp/raspberrypi/link.ld
|
|
||||||
+++ 04_zero_overhead_abstraction/src/bsp/raspberrypi/link.ld
|
|
||||||
@@ -21,6 +21,7 @@
|
|
||||||
/***********************************************************************************************
|
|
||||||
* Code + RO Data + Global Offset Table
|
|
||||||
***********************************************************************************************/
|
|
||||||
+ __rx_start = .;
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
KEEP(*(.text._start))
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi/memory.rs 04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs
|
|
||||||
--- 03_hacky_hello_world/src/bsp/raspberrypi/memory.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/bsp/raspberrypi/memory.rs
|
|
||||||
@@ -12,14 +12,36 @@
|
|
||||||
|
|
||||||
// Symbols from the linker script.
|
|
||||||
extern "Rust" {
|
|
||||||
+ static __rx_start: UnsafeCell<()>;
|
|
||||||
+
|
|
||||||
static __bss_start: UnsafeCell<u64>;
|
|
||||||
static __bss_end_inclusive: UnsafeCell<u64>;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
+// Private Code
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+
|
|
||||||
+/// Start address of the Read+Execute (RX) range.
|
|
||||||
+///
|
|
||||||
+/// # Safety
|
|
||||||
+///
|
|
||||||
+/// - Value is provided by the linker script and must be trusted as-is.
|
|
||||||
+#[inline(always)]
|
|
||||||
+fn rx_start() -> usize {
|
|
||||||
+ unsafe { __rx_start.get() as usize }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
+/// Exclusive end address of the boot core's stack.
|
|
||||||
+#[inline(always)]
|
|
||||||
+pub fn boot_core_stack_end() -> usize {
|
|
||||||
+ rx_start()
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/// Return the inclusive range spanning the .bss section.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/bsp/raspberrypi.rs 04_zero_overhead_abstraction/src/bsp/raspberrypi.rs
|
|
||||||
--- 03_hacky_hello_world/src/bsp/raspberrypi.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/bsp/raspberrypi.rs
|
|
||||||
@@ -5,4 +5,5 @@
|
|
||||||
//! Top-level BSP file for the Raspberry Pi 3 and 4.
|
|
||||||
|
|
||||||
pub mod console;
|
|
||||||
+pub mod cpu;
|
|
||||||
pub mod memory;
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/cpu/smp.rs 04_zero_overhead_abstraction/src/cpu/smp.rs
|
|
||||||
--- 03_hacky_hello_world/src/cpu/smp.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/cpu/smp.rs
|
|
||||||
@@ -0,0 +1,14 @@
|
|
||||||
+// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
+//
|
|
||||||
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
+
|
|
||||||
+//! Symmetric multiprocessing.
|
|
||||||
+
|
|
||||||
+#[cfg(target_arch = "aarch64")]
|
|
||||||
+#[path = "../_arch/aarch64/cpu/smp.rs"]
|
|
||||||
+mod arch_smp;
|
|
||||||
+
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+// Architectural Public Reexports
|
|
||||||
+//--------------------------------------------------------------------------------------------------
|
|
||||||
+pub use arch_smp::core_id;
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/cpu.rs 04_zero_overhead_abstraction/src/cpu.rs
|
|
||||||
--- 03_hacky_hello_world/src/cpu.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/cpu.rs
|
|
||||||
@@ -10,6 +10,8 @@
|
|
||||||
|
|
||||||
mod boot;
|
|
||||||
|
|
||||||
+pub mod smp;
|
|
||||||
+
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Architectural Public Reexports
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/main.rs 04_zero_overhead_abstraction/src/main.rs
|
|
||||||
--- 03_hacky_hello_world/src/main.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/main.rs
|
|
||||||
@@ -107,9 +107,7 @@
|
|
||||||
//! [`cpu::boot::arch_boot::_start()`]: cpu/boot/arch_boot/fn._start.html
|
|
||||||
//! [`runtime_init::runtime_init()`]: runtime_init/fn.runtime_init.html
|
|
||||||
|
|
||||||
-#![feature(asm)]
|
|
||||||
#![feature(format_args_nl)]
|
|
||||||
-#![feature(global_asm)]
|
|
||||||
#![feature(panic_info_message)]
|
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
@@ -128,7 +126,8 @@
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
unsafe fn kernel_init() -> ! {
|
|
||||||
- println!("[0] Hello from Rust!");
|
|
||||||
+ println!("[0] Hello from pure Rust!");
|
|
||||||
|
|
||||||
- panic!("Stopping here.")
|
|
||||||
+ println!("[1] Stopping here.");
|
|
||||||
+ cpu::wait_forever()
|
|
||||||
}
|
|
||||||
|
|
||||||
diff -uNr 03_hacky_hello_world/src/runtime_init.rs 04_zero_overhead_abstraction/src/runtime_init.rs
|
|
||||||
--- 03_hacky_hello_world/src/runtime_init.rs
|
|
||||||
+++ 04_zero_overhead_abstraction/src/runtime_init.rs
|
|
||||||
@@ -30,7 +30,6 @@
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
-#[no_mangle]
|
|
||||||
pub unsafe fn runtime_init() -> ! {
|
|
||||||
zero_bss();
|
|
||||||
|
|
||||||
```
|
|
@ -1,8 +0,0 @@
|
|||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let linker_file = env::var("LINKER_FILE").unwrap();
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed={}", linker_file);
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural processor code.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::arch_cpu
|
|
||||||
|
|
||||||
use cortex_a::asm;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Pause execution on the core.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn wait_forever() -> ! {
|
|
||||||
loop {
|
|
||||||
asm::wfe()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural boot code.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::boot::arch_boot
|
|
||||||
|
|
||||||
use crate::{bsp, cpu};
|
|
||||||
use cortex_a::regs::*;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// The entry of the `kernel` binary.
|
|
||||||
///
|
|
||||||
/// The function must be named `_start`, because the linker is looking for this exact name.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Linker script must ensure to place this function where it is expected by the target machine.
|
|
||||||
/// - We have to hope that the compiler omits any stack pointer usage before the stack pointer is
|
|
||||||
/// actually set (`SP.set()`).
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe fn _start() -> ! {
|
|
||||||
use crate::runtime_init;
|
|
||||||
|
|
||||||
if bsp::cpu::BOOT_CORE_ID == cpu::smp::core_id() {
|
|
||||||
SP.set(bsp::memory::boot_core_stack_end() as u64);
|
|
||||||
runtime_init::runtime_init()
|
|
||||||
} else {
|
|
||||||
// If not core0, infinitely wait for events.
|
|
||||||
cpu::wait_forever()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural symmetric multiprocessing.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::smp::arch_smp
|
|
||||||
|
|
||||||
use cortex_a::regs::*;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Return the executing core's id.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn core_id<T>() -> T
|
|
||||||
where
|
|
||||||
T: From<u8>,
|
|
||||||
{
|
|
||||||
const CORE_MASK: u64 = 0b11;
|
|
||||||
|
|
||||||
T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Conditional reexporting of Board Support Packages.
|
|
||||||
|
|
||||||
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
|
||||||
mod raspberrypi;
|
|
||||||
|
|
||||||
#[cfg(any(feature = "bsp_rpi3", feature = "bsp_rpi4"))]
|
|
||||||
pub use raspberrypi::*;
|
|
@ -1,9 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Top-level BSP file for the Raspberry Pi 3 and 4.
|
|
||||||
|
|
||||||
pub mod console;
|
|
||||||
pub mod cpu;
|
|
||||||
pub mod memory;
|
|
@ -1,47 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! BSP console facilities.
|
|
||||||
|
|
||||||
use crate::console;
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Private Definitions
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// A mystical, magical device for generating QEMU output out of the void.
|
|
||||||
struct QEMUOutput;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Private Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Implementing `core::fmt::Write` enables usage of the `format_args!` macros, which in turn are
|
|
||||||
/// used to implement the `kernel`'s `print!` and `println!` macros. By implementing `write_str()`,
|
|
||||||
/// we get `write_fmt()` automatically.
|
|
||||||
///
|
|
||||||
/// See [`src/print.rs`].
|
|
||||||
///
|
|
||||||
/// [`src/print.rs`]: ../../print/index.html
|
|
||||||
impl fmt::Write for QEMUOutput {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
for c in s.chars() {
|
|
||||||
unsafe {
|
|
||||||
core::ptr::write_volatile(0x3F20_1000 as *mut u8, c as u8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Return a reference to the console.
|
|
||||||
pub fn console() -> impl console::interface::Write {
|
|
||||||
QEMUOutput {}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The address at which the the kernel binary will be loaded by the Raspberry's firmware */
|
|
||||||
__rpi_load_addr = 0x80000;
|
|
||||||
|
|
||||||
ENTRY(__rpi_load_addr)
|
|
||||||
|
|
||||||
PHDRS
|
|
||||||
{
|
|
||||||
segment_rx PT_LOAD FLAGS(5); /* 5 == RX */
|
|
||||||
segment_rw PT_LOAD FLAGS(6); /* 6 == RW */
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
. = __rpi_load_addr;
|
|
||||||
|
|
||||||
/***********************************************************************************************
|
|
||||||
* Code + RO Data + Global Offset Table
|
|
||||||
***********************************************************************************************/
|
|
||||||
__rx_start = .;
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
KEEP(*(.text._start))
|
|
||||||
*(.text*)
|
|
||||||
} :segment_rx
|
|
||||||
|
|
||||||
.rodata : ALIGN(8) { *(.rodata*) } :segment_rx
|
|
||||||
.got : ALIGN(8) { *(.got) } :segment_rx
|
|
||||||
|
|
||||||
/***********************************************************************************************
|
|
||||||
* Data + BSS
|
|
||||||
***********************************************************************************************/
|
|
||||||
.data : { *(.data*) } :segment_rw
|
|
||||||
|
|
||||||
/* Section is zeroed in u64 chunks, align start and end to 8 bytes */
|
|
||||||
.bss : ALIGN(8)
|
|
||||||
{
|
|
||||||
__bss_start = .;
|
|
||||||
*(.bss*);
|
|
||||||
. = ALIGN(8);
|
|
||||||
|
|
||||||
. += 8; /* Fill for the bss == 0 case, so that __bss_start <= __bss_end_inclusive holds */
|
|
||||||
__bss_end_inclusive = . - 8;
|
|
||||||
} :NONE
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! BSP Memory Management.
|
|
||||||
|
|
||||||
use core::{cell::UnsafeCell, ops::RangeInclusive};
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Private Definitions
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Symbols from the linker script.
|
|
||||||
extern "Rust" {
|
|
||||||
static __rx_start: UnsafeCell<()>;
|
|
||||||
|
|
||||||
static __bss_start: UnsafeCell<u64>;
|
|
||||||
static __bss_end_inclusive: UnsafeCell<u64>;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Private Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Start address of the Read+Execute (RX) range.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Value is provided by the linker script and must be trusted as-is.
|
|
||||||
#[inline(always)]
|
|
||||||
fn rx_start() -> usize {
|
|
||||||
unsafe { __rx_start.get() as usize }
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Exclusive end address of the boot core's stack.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn boot_core_stack_end() -> usize {
|
|
||||||
rx_start()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the inclusive range spanning the .bss section.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Values are provided by the linker script and must be trusted as-is.
|
|
||||||
/// - The linker-provided addresses must be u64 aligned.
|
|
||||||
pub fn bss_range_inclusive() -> RangeInclusive<*mut u64> {
|
|
||||||
let range;
|
|
||||||
unsafe {
|
|
||||||
range = RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get());
|
|
||||||
}
|
|
||||||
assert!(!range.is_empty());
|
|
||||||
|
|
||||||
range
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! System console.
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Definitions
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Console interfaces.
|
|
||||||
pub mod interface {
|
|
||||||
/// Console write functions.
|
|
||||||
///
|
|
||||||
/// `core::fmt::Write` is exactly what we need for now. Re-export it here because
|
|
||||||
/// implementing `console::Write` gives a better hint to the reader about the
|
|
||||||
/// intention.
|
|
||||||
pub use core::fmt::Write;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2020-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Processor code.
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[path = "_arch/aarch64/cpu.rs"]
|
|
||||||
mod arch_cpu;
|
|
||||||
|
|
||||||
mod boot;
|
|
||||||
|
|
||||||
pub mod smp;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Architectural Public Reexports
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
pub use arch_cpu::wait_forever;
|
|
@ -1,9 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Boot code.
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[path = "../_arch/aarch64/cpu/boot.rs"]
|
|
||||||
mod arch_boot;
|
|
@ -1,133 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
// Rust embedded logo for `make doc`.
|
|
||||||
#![doc(html_logo_url = "https://git.io/JeGIp")]
|
|
||||||
|
|
||||||
//! The `kernel` binary.
|
|
||||||
//!
|
|
||||||
//! # Code organization and architecture
|
|
||||||
//!
|
|
||||||
//! The code is divided into different *modules*, each representing a typical **subsystem** of the
|
|
||||||
//! `kernel`. Top-level module files of subsystems reside directly in the `src` folder. For example,
|
|
||||||
//! `src/memory.rs` contains code that is concerned with all things memory management.
|
|
||||||
//!
|
|
||||||
//! ## Visibility of processor architecture code
|
|
||||||
//!
|
|
||||||
//! Some of the `kernel`'s subsystems depend on low-level code that is specific to the target
|
|
||||||
//! processor architecture. For each supported processor architecture, there exists a subfolder in
|
|
||||||
//! `src/_arch`, for example, `src/_arch/aarch64`.
|
|
||||||
//!
|
|
||||||
//! The architecture folders mirror the subsystem modules laid out in `src`. For example,
|
|
||||||
//! architectural code that belongs to the `kernel`'s MMU subsystem (`src/memory/mmu.rs`) would go
|
|
||||||
//! into `src/_arch/aarch64/memory/mmu.rs`. The latter file is loaded as a module in
|
|
||||||
//! `src/memory/mmu.rs` using the `path attribute`. Usually, the chosen module name is the generic
|
|
||||||
//! module's name prefixed with `arch_`.
|
|
||||||
//!
|
|
||||||
//! For example, this is the top of `src/memory/mmu.rs`:
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! #[cfg(target_arch = "aarch64")]
|
|
||||||
//! #[path = "../_arch/aarch64/memory/mmu.rs"]
|
|
||||||
//! mod arch_mmu;
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Often times, items from the `arch_ module` will be publicly reexported by the parent module.
|
|
||||||
//! This way, each architecture specific module can provide its implementation of an item, while the
|
|
||||||
//! caller must not be concerned which architecture has been conditionally compiled.
|
|
||||||
//!
|
|
||||||
//! ## BSP code
|
|
||||||
//!
|
|
||||||
//! `BSP` stands for Board Support Package. `BSP` code is organized under `src/bsp.rs` and contains
|
|
||||||
//! target board specific definitions and functions. These are things such as the board's memory map
|
|
||||||
//! or instances of drivers for devices that are featured on the respective board.
|
|
||||||
//!
|
|
||||||
//! Just like processor architecture code, the `BSP` code's module structure tries to mirror the
|
|
||||||
//! `kernel`'s subsystem modules, but there is no reexporting this time. That means whatever is
|
|
||||||
//! provided must be called starting from the `bsp` namespace, e.g. `bsp::driver::driver_manager()`.
|
|
||||||
//!
|
|
||||||
//! ## Kernel interfaces
|
|
||||||
//!
|
|
||||||
//! Both `arch` and `bsp` contain code that is conditionally compiled depending on the actual target
|
|
||||||
//! and board for which the kernel is compiled. For example, the `interrupt controller` hardware of
|
|
||||||
//! the `Raspberry Pi 3` and the `Raspberry Pi 4` is different, but we want the rest of the `kernel`
|
|
||||||
//! code to play nicely with any of the two without much hassle.
|
|
||||||
//!
|
|
||||||
//! In order to provide a clean abstraction between `arch`, `bsp` and `generic kernel code`,
|
|
||||||
//! `interface` traits are provided *whenever possible* and *where it makes sense*. They are defined
|
|
||||||
//! in the respective subsystem module and help to enforce the idiom of *program to an interface,
|
|
||||||
//! not an implementation*. For example, there will be a common IRQ handling interface which the two
|
|
||||||
//! different interrupt controller `drivers` of both Raspberrys will implement, and only export the
|
|
||||||
//! interface to the rest of the `kernel`.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! +-------------------+
|
|
||||||
//! | Interface (Trait) |
|
|
||||||
//! | |
|
|
||||||
//! +--+-------------+--+
|
|
||||||
//! ^ ^
|
|
||||||
//! | |
|
|
||||||
//! | |
|
|
||||||
//! +----------+--+ +--+----------+
|
|
||||||
//! | kernel code | | bsp code |
|
|
||||||
//! | | | arch code |
|
|
||||||
//! +-------------+ +-------------+
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! # Summary
|
|
||||||
//!
|
|
||||||
//! For a logical `kernel` subsystem, corresponding code can be distributed over several physical
|
|
||||||
//! locations. Here is an example for the **memory** subsystem:
|
|
||||||
//!
|
|
||||||
//! - `src/memory.rs` and `src/memory/**/*`
|
|
||||||
//! - Common code that is agnostic of target processor architecture and `BSP` characteristics.
|
|
||||||
//! - Example: A function to zero a chunk of memory.
|
|
||||||
//! - Interfaces for the memory subsystem that are implemented by `arch` or `BSP` code.
|
|
||||||
//! - Example: An `MMU` interface that defines `MMU` function prototypes.
|
|
||||||
//! - `src/bsp/__board_name__/memory.rs` and `src/bsp/__board_name__/memory/**/*`
|
|
||||||
//! - `BSP` specific code.
|
|
||||||
//! - Example: The board's memory map (physical addresses of DRAM and MMIO devices).
|
|
||||||
//! - `src/_arch/__arch_name__/memory.rs` and `src/_arch/__arch_name__/memory/**/*`
|
|
||||||
//! - Processor architecture specific code.
|
|
||||||
//! - Example: Implementation of the `MMU` interface for the `__arch_name__` processor
|
|
||||||
//! architecture.
|
|
||||||
//!
|
|
||||||
//! From a namespace perspective, **memory** subsystem code lives in:
|
|
||||||
//!
|
|
||||||
//! - `crate::memory::*`
|
|
||||||
//! - `crate::bsp::memory::*`
|
|
||||||
//!
|
|
||||||
//! # Boot flow
|
|
||||||
//!
|
|
||||||
//! 1. The kernel's entry point is the function [`cpu::boot::arch_boot::_start()`].
|
|
||||||
//! - It is implemented in `src/_arch/__arch_name__/cpu/boot.rs`.
|
|
||||||
//! 2. Once finished with architectural setup, the arch code calls [`runtime_init::runtime_init()`].
|
|
||||||
//!
|
|
||||||
//! [`cpu::boot::arch_boot::_start()`]: cpu/boot/arch_boot/fn._start.html
|
|
||||||
//! [`runtime_init::runtime_init()`]: runtime_init/fn.runtime_init.html
|
|
||||||
|
|
||||||
#![feature(format_args_nl)]
|
|
||||||
#![feature(panic_info_message)]
|
|
||||||
#![no_main]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
mod bsp;
|
|
||||||
mod console;
|
|
||||||
mod cpu;
|
|
||||||
mod memory;
|
|
||||||
mod panic_wait;
|
|
||||||
mod print;
|
|
||||||
mod runtime_init;
|
|
||||||
|
|
||||||
/// Early init code.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
unsafe fn kernel_init() -> ! {
|
|
||||||
println!("[0] Hello from pure Rust!");
|
|
||||||
|
|
||||||
println!("[1] Stopping here.");
|
|
||||||
cpu::wait_forever()
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Memory Management.
|
|
||||||
|
|
||||||
use core::ops::RangeInclusive;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Zero out an inclusive memory range.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - `range.start` and `range.end` must be valid.
|
|
||||||
/// - `range.start` and `range.end` must be `T` aligned.
|
|
||||||
pub unsafe fn zero_volatile<T>(range: RangeInclusive<*mut T>)
|
|
||||||
where
|
|
||||||
T: From<u8>,
|
|
||||||
{
|
|
||||||
let mut ptr = *range.start();
|
|
||||||
let end_inclusive = *range.end();
|
|
||||||
|
|
||||||
while ptr <= end_inclusive {
|
|
||||||
core::ptr::write_volatile(ptr, T::from(0));
|
|
||||||
ptr = ptr.offset(1);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! A panic handler that infinitely waits.
|
|
||||||
|
|
||||||
use crate::{cpu, println};
|
|
||||||
use core::panic::PanicInfo;
|
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
|
||||||
if let Some(args) = info.message() {
|
|
||||||
println!("\nKernel panic: {}", args);
|
|
||||||
} else {
|
|
||||||
println!("\nKernel panic!");
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu::wait_forever()
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Printing.
|
|
||||||
|
|
||||||
use crate::{bsp, console};
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub fn _print(args: fmt::Arguments) {
|
|
||||||
use console::interface::Write;
|
|
||||||
|
|
||||||
bsp::console::console().write_fmt(args).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints without a newline.
|
|
||||||
///
|
|
||||||
/// Carbon copy from <https://doc.rust-lang.org/src/std/macros.rs.html>
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => ($crate::print::_print(format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints with a newline.
|
|
||||||
///
|
|
||||||
/// Carbon copy from <https://doc.rust-lang.org/src/std/macros.rs.html>
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
() => ($crate::print!("\n"));
|
|
||||||
($($arg:tt)*) => ({
|
|
||||||
$crate::print::_print(format_args_nl!($($arg)*));
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Rust runtime initialization code.
|
|
||||||
|
|
||||||
use crate::{bsp, memory};
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Private Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Zero out the .bss section.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Must only be called pre `kernel_init()`.
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn zero_bss() {
|
|
||||||
memory::zero_volatile(bsp::memory::bss_range_inclusive());
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Equivalent to `crt0` or `c0` code in C/C++ world. Clears the `bss` section, then jumps to kernel
|
|
||||||
/// init code.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
pub unsafe fn runtime_init() -> ! {
|
|
||||||
zero_bss();
|
|
||||||
|
|
||||||
crate::kernel_init()
|
|
||||||
}
|
|
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ _core_id_mask, 0b11
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Only proceed on the boot core. Park it otherwise.
|
||||||
|
mrs x1, MPIDR_EL1
|
||||||
|
and x1, x1, _core_id_mask
|
||||||
|
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
|
||||||
|
cmp x1, x2
|
||||||
|
b.ne 1f
|
||||||
|
|
||||||
|
// If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
|
||||||
|
|
||||||
|
// Set the stack pointer.
|
||||||
|
ldr x0, =__boot_core_stack_end_exclusive
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
// Jump to Rust code.
|
||||||
|
b _start_rust
|
||||||
|
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,29 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural symmetric multiprocessing.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::smp::arch_smp
|
|
||||||
|
|
||||||
use cortex_a::regs::*;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Return the executing core's id.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn core_id<T>() -> T
|
|
||||||
where
|
|
||||||
T: From<u8>,
|
|
||||||
{
|
|
||||||
const CORE_MASK: u64 = 0b11;
|
|
||||||
|
|
||||||
T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Symmetric multiprocessing.
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[path = "../_arch/aarch64/cpu/smp.rs"]
|
|
||||||
mod arch_smp;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Architectural Public Reexports
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
pub use arch_smp::core_id;
|
|
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ _core_id_mask, 0b11
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Only proceed on the boot core. Park it otherwise.
|
||||||
|
mrs x1, MPIDR_EL1
|
||||||
|
and x1, x1, _core_id_mask
|
||||||
|
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
|
||||||
|
cmp x1, x2
|
||||||
|
b.ne 1f
|
||||||
|
|
||||||
|
// If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
|
||||||
|
|
||||||
|
// Set the stack pointer.
|
||||||
|
ldr x0, =__boot_core_stack_end_exclusive
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
// Jump to Rust code.
|
||||||
|
b _start_rust
|
||||||
|
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,29 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural symmetric multiprocessing.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::smp::arch_smp
|
|
||||||
|
|
||||||
use cortex_a::regs::*;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Return the executing core's id.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn core_id<T>() -> T
|
|
||||||
where
|
|
||||||
T: From<u8>,
|
|
||||||
{
|
|
||||||
const CORE_MASK: u64 = 0b11;
|
|
||||||
|
|
||||||
T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Symmetric multiprocessing.
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[path = "../_arch/aarch64/cpu/smp.rs"]
|
|
||||||
mod arch_smp;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Architectural Public Reexports
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
pub use arch_smp::core_id;
|
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,53 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ _core_id_mask, 0b11
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Only proceed on the boot core. Park it otherwise.
|
||||||
|
mrs x1, MPIDR_EL1
|
||||||
|
and x1, x1, _core_id_mask
|
||||||
|
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
|
||||||
|
cmp x1, x2
|
||||||
|
b.ne 2f
|
||||||
|
|
||||||
|
// If execution reaches here, it is the boot core.
|
||||||
|
|
||||||
|
// Next, relocate the binary.
|
||||||
|
adr x0, __binary_nonzero_start // The address the binary got loaded to.
|
||||||
|
ldr x1, =__binary_nonzero_start // The address the binary was linked to.
|
||||||
|
ldr x2, =__binary_nonzero_end_exclusive
|
||||||
|
|
||||||
|
1: ldr x3, [x0], #8
|
||||||
|
str x3, [x1], #8
|
||||||
|
cmp x1, x2
|
||||||
|
b.lo 1b
|
||||||
|
|
||||||
|
// Set the stack pointer.
|
||||||
|
ldr x0, =__boot_core_stack_end_exclusive
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
// Jump to the relocated Rust code.
|
||||||
|
ldr x1, =_start_rust
|
||||||
|
br x1
|
||||||
|
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
2: wfe
|
||||||
|
b 2b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,29 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural symmetric multiprocessing.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::smp::arch_smp
|
|
||||||
|
|
||||||
use cortex_a::regs::*;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Return the executing core's id.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn core_id<T>() -> T
|
|
||||||
where
|
|
||||||
T: From<u8>,
|
|
||||||
{
|
|
||||||
const CORE_MASK: u64 = 0b11;
|
|
||||||
|
|
||||||
T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Symmetric multiprocessing.
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[path = "../_arch/aarch64/cpu/smp.rs"]
|
|
||||||
mod arch_smp;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Architectural Public Reexports
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
pub use arch_smp::core_id;
|
|
@ -1,49 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Relocation code.
|
|
||||||
|
|
||||||
use crate::{bsp, cpu};
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Relocates the own binary from `bsp::memory::board_default_load_addr()` to the `__binary_start`
|
|
||||||
/// address from the linker script.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - Only a single core must be active and running this function.
|
|
||||||
/// - Function must not use the `bss` section.
|
|
||||||
#[inline(never)]
|
|
||||||
pub unsafe fn relocate_self() -> ! {
|
|
||||||
let range = bsp::memory::relocated_binary_range_inclusive();
|
|
||||||
let mut relocated_binary_start_addr = *range.start();
|
|
||||||
let relocated_binary_end_addr_inclusive = *range.end();
|
|
||||||
|
|
||||||
// The address of where the previous firmware loaded us.
|
|
||||||
let mut current_binary_start_addr = bsp::memory::board_default_load_addr();
|
|
||||||
|
|
||||||
// Copy the whole binary.
|
|
||||||
while relocated_binary_start_addr <= relocated_binary_end_addr_inclusive {
|
|
||||||
core::ptr::write_volatile(
|
|
||||||
relocated_binary_start_addr,
|
|
||||||
core::ptr::read_volatile(current_binary_start_addr),
|
|
||||||
);
|
|
||||||
relocated_binary_start_addr = relocated_binary_start_addr.offset(1);
|
|
||||||
current_binary_start_addr = current_binary_start_addr.offset(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following function calls realize an "absolute jump" to `runtime_init::runtime_init()` by
|
|
||||||
// forcing an indirection through the global offset table (GOT), so that execution continues
|
|
||||||
// from the relocated binary.
|
|
||||||
//
|
|
||||||
// Without the indirection through the assembly, the address of `runtime_init()` would be
|
|
||||||
// calculated as a relative offset from the current program counter, since we are compiling as
|
|
||||||
// `position independent code`. This would cause us to keep executing from the address to which
|
|
||||||
// the firmware loaded us, instead of the relocated position.
|
|
||||||
let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize;
|
|
||||||
cpu::branch_to_raw_addr(relocated_runtime_init_addr)
|
|
||||||
}
|
|
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Definitions
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ _core_id_mask, 0b11
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
// Public Code
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
.section .text._start
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// fn _start()
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
_start:
|
||||||
|
// Only proceed on the boot core. Park it otherwise.
|
||||||
|
mrs x1, MPIDR_EL1
|
||||||
|
and x1, x1, _core_id_mask
|
||||||
|
ldr x2, BOOT_CORE_ID // provided by bsp/__board_name__/cpu.rs
|
||||||
|
cmp x1, x2
|
||||||
|
b.ne 1f
|
||||||
|
|
||||||
|
// If execution reaches here, it is the boot core. Now, prepare the jump to Rust code.
|
||||||
|
|
||||||
|
// Set the stack pointer.
|
||||||
|
ldr x0, =__boot_core_stack_end_exclusive
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
// Jump to Rust code.
|
||||||
|
b _start_rust
|
||||||
|
|
||||||
|
// Infinitely wait for events (aka "park the core").
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
|
||||||
|
.size _start, . - _start
|
||||||
|
.type _start, function
|
||||||
|
.global _start
|
@ -1,29 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Architectural symmetric multiprocessing.
|
|
||||||
//!
|
|
||||||
//! # Orientation
|
|
||||||
//!
|
|
||||||
//! Since arch modules are imported into generic modules using the path attribute, the path of this
|
|
||||||
//! file is:
|
|
||||||
//!
|
|
||||||
//! crate::cpu::smp::arch_smp
|
|
||||||
|
|
||||||
use cortex_a::regs::*;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Public Code
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// Return the executing core's id.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn core_id<T>() -> T
|
|
||||||
where
|
|
||||||
T: From<u8>,
|
|
||||||
{
|
|
||||||
const CORE_MASK: u64 = 0b11;
|
|
||||||
|
|
||||||
T::from((MPIDR_EL1.get() & CORE_MASK) as u8)
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
|
||||||
|
|
||||||
//! Symmetric multiprocessing.
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
#[path = "../_arch/aarch64/cpu/smp.rs"]
|
|
||||||
mod arch_smp;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Architectural Public Reexports
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
pub use arch_smp::core_id;
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue