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.
|
||||
# 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,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.
|
||||
# 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,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