|
|
|
@ -202,6 +202,26 @@ diff -uNr 06_drivers_gpio_uart/src/_arch/aarch64/cpu.rs 07_uart_chainloader/src/
|
|
|
|
|
} else {
|
|
|
|
|
// If not core0, infinitely wait for events.
|
|
|
|
|
wait_forever()
|
|
|
|
|
@@ -54,3 +54,19 @@
|
|
|
|
|
asm::wfe()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+/// Branch to a raw integer value.
|
|
|
|
|
+///
|
|
|
|
|
+/// # Safety
|
|
|
|
|
+///
|
|
|
|
|
+/// - This is highly unsafe. Use with care.
|
|
|
|
|
+#[inline(always)]
|
|
|
|
|
+pub unsafe fn branch_to_raw_addr(addr: usize) -> ! {
|
|
|
|
|
+ asm!(
|
|
|
|
|
+ "blr {destination:x}",
|
|
|
|
|
+ destination = in(reg) addr,
|
|
|
|
|
+ options(nomem, nostack)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ core::intrinsics::unreachable()
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 07_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
|
|
|
|
|
--- 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs
|
|
|
|
@ -258,7 +278,7 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs 0
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld 07_uart_chainloader/src/bsp/raspberrypi/link.ld
|
|
|
|
|
--- 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld
|
|
|
|
|
+++ 07_uart_chainloader/src/bsp/raspberrypi/link.ld
|
|
|
|
|
@@ -5,9 +5,10 @@
|
|
|
|
|
@@ -5,12 +5,16 @@
|
|
|
|
|
|
|
|
|
|
SECTIONS
|
|
|
|
|
{
|
|
|
|
@ -270,8 +290,15 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld 07_uart_chainloader/s
|
|
|
|
|
+ __binary_start = .;
|
|
|
|
|
.text :
|
|
|
|
|
{
|
|
|
|
|
*(.text._start) *(.text*)
|
|
|
|
|
@@ -32,5 +33,14 @@
|
|
|
|
|
- *(.text._start) *(.text*)
|
|
|
|
|
+ *(.text._start)
|
|
|
|
|
+ __runtime_init = .;
|
|
|
|
|
+ KEEP(*(.text.runtime_init))
|
|
|
|
|
+ *(.text*);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.rodata :
|
|
|
|
|
@@ -32,5 +36,14 @@
|
|
|
|
|
__bss_end_inclusive = . - 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -290,16 +317,17 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/link.ld 07_uart_chainloader/s
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 07_uart_chainloader/src/bsp/raspberrypi/memory.rs
|
|
|
|
|
--- 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs
|
|
|
|
|
+++ 07_uart_chainloader/src/bsp/raspberrypi/memory.rs
|
|
|
|
|
@@ -12,6 +12,8 @@
|
|
|
|
|
@@ -12,6 +12,9 @@
|
|
|
|
|
|
|
|
|
|
// Symbols from the linker script.
|
|
|
|
|
extern "Rust" {
|
|
|
|
|
+ static __binary_start: UnsafeCell<u64>;
|
|
|
|
|
+ static __binary_end_inclusive: UnsafeCell<u64>;
|
|
|
|
|
+ static __runtime_init: UnsafeCell<u64>;
|
|
|
|
|
static __bss_start: UnsafeCell<u64>;
|
|
|
|
|
static __bss_end_inclusive: UnsafeCell<u64>;
|
|
|
|
|
}
|
|
|
|
|
@@ -23,10 +25,12 @@
|
|
|
|
|
@@ -23,10 +26,12 @@
|
|
|
|
|
/// The board's memory map.
|
|
|
|
|
#[rustfmt::skip]
|
|
|
|
|
pub(super) mod map {
|
|
|
|
@ -315,29 +343,43 @@ diff -uNr 06_drivers_gpio_uart/src/bsp/raspberrypi/memory.rs 07_uart_chainloader
|
|
|
|
|
|
|
|
|
|
/// Physical devices.
|
|
|
|
|
#[cfg(feature = "bsp_rpi3")]
|
|
|
|
|
@@ -59,6 +63,22 @@
|
|
|
|
|
@@ -59,12 +64,34 @@
|
|
|
|
|
map::BOOT_CORE_STACK_END
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-/// Return the inclusive range spanning the .bss section.
|
|
|
|
|
+/// The address on which the Raspberry firmware loads every binary by default.
|
|
|
|
|
+#[inline(always)]
|
|
|
|
|
+pub fn board_default_load_addr() -> *const u64 {
|
|
|
|
|
+ map::BOARD_DEFAULT_LOAD_ADDRESS as _
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// Return the inclusive range spanning the whole binary.
|
|
|
|
|
+/// Return the inclusive range spanning the relocated kernel binary.
|
|
|
|
|
+///
|
|
|
|
|
+/// # Safety
|
|
|
|
|
+///
|
|
|
|
|
+/// - Values are provided by the linker script and must be trusted as-is.
|
|
|
|
|
+/// - The linker-provided addresses must be u64 aligned.
|
|
|
|
|
+pub fn binary_range_inclusive() -> RangeInclusive<*mut u64> {
|
|
|
|
|
+pub fn relocated_binary_range_inclusive() -> RangeInclusive<*mut u64> {
|
|
|
|
|
+ unsafe { RangeInclusive::new(__binary_start.get(), __binary_end_inclusive.get()) }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
/// Return the inclusive range spanning the .bss section.
|
|
|
|
|
+/// The relocated address of function `runtime_init()`.
|
|
|
|
|
+#[inline(always)]
|
|
|
|
|
+pub fn relocated_runtime_init_addr() -> *const u64 {
|
|
|
|
|
+ unsafe { __runtime_init.get() as _ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// Return the inclusive range spanning the relocated .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> {
|
|
|
|
|
+pub fn relocated_bss_range_inclusive() -> RangeInclusive<*mut u64> {
|
|
|
|
|
unsafe { RangeInclusive::new(__bss_start.get(), __bss_end_inclusive.get()) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/console.rs 07_uart_chainloader/src/console.rs
|
|
|
|
|
--- 06_drivers_gpio_uart/src/console.rs
|
|
|
|
@ -367,7 +409,16 @@ diff -uNr 06_drivers_gpio_uart/src/console.rs 07_uart_chainloader/src/console.rs
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
|
|
|
|
|
--- 06_drivers_gpio_uart/src/main.rs
|
|
|
|
|
+++ 07_uart_chainloader/src/main.rs
|
|
|
|
|
@@ -108,7 +108,8 @@
|
|
|
|
|
@@ -100,6 +100,8 @@
|
|
|
|
|
//! - `crate::memory::*`
|
|
|
|
|
//! - `crate::bsp::memory::*`
|
|
|
|
|
|
|
|
|
|
+#![feature(asm)]
|
|
|
|
|
+#![feature(core_intrinsics)]
|
|
|
|
|
#![feature(format_args_nl)]
|
|
|
|
|
#![feature(naked_functions)]
|
|
|
|
|
#![feature(panic_info_message)]
|
|
|
|
|
@@ -108,7 +110,8 @@
|
|
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
|
|
// `mod cpu` provides the `_start()` function, the first function to run. `_start()` then calls
|
|
|
|
@ -377,7 +428,7 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
|
|
|
|
|
|
|
|
|
|
mod bsp;
|
|
|
|
|
mod console;
|
|
|
|
|
@@ -117,6 +118,7 @@
|
|
|
|
|
@@ -117,6 +120,7 @@
|
|
|
|
|
mod memory;
|
|
|
|
|
mod panic_wait;
|
|
|
|
|
mod print;
|
|
|
|
@ -385,7 +436,7 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
|
|
|
|
|
mod runtime_init;
|
|
|
|
|
mod synchronization;
|
|
|
|
|
|
|
|
|
|
@@ -143,35 +145,52 @@
|
|
|
|
|
@@ -143,35 +147,52 @@
|
|
|
|
|
|
|
|
|
|
/// The main function running after the early init.
|
|
|
|
|
fn kernel_main() -> ! {
|
|
|
|
@ -447,7 +498,7 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
|
|
|
|
|
- println!(" {}. {}", i + 1, driver.compatible());
|
|
|
|
|
- }
|
|
|
|
|
+ // Use black magic to get a function pointer.
|
|
|
|
|
+ let kernel: fn() -> ! = unsafe { core::mem::transmute(kernel_addr as *const ()) };
|
|
|
|
|
+ let kernel: fn() -> ! = unsafe { core::mem::transmute(kernel_addr) };
|
|
|
|
|
|
|
|
|
|
- println!(
|
|
|
|
|
- "[2] Chars written: {}",
|
|
|
|
@ -466,55 +517,81 @@ diff -uNr 06_drivers_gpio_uart/src/main.rs 07_uart_chainloader/src/main.rs
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/relocate.rs 07_uart_chainloader/src/relocate.rs
|
|
|
|
|
--- 06_drivers_gpio_uart/src/relocate.rs
|
|
|
|
|
+++ 07_uart_chainloader/src/relocate.rs
|
|
|
|
|
@@ -0,0 +1,49 @@
|
|
|
|
|
@@ -0,0 +1,55 @@
|
|
|
|
|
+// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
|
+//
|
|
|
|
|
+// Copyright (c) 2018-2020 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
|
+
|
|
|
|
|
+//! Relocation code.
|
|
|
|
|
+
|
|
|
|
|
+use crate::{bsp, runtime_init};
|
|
|
|
|
+use crate::{bsp, cpu};
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Public Code
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+/// Relocates the own binary from `bsp::cpu::BOARD_DEFAULT_LOAD_ADDRESS` to the `__binary_start`
|
|
|
|
|
+/// 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::binary_range_inclusive();
|
|
|
|
|
+ let mut reloc_destination_addr = *range.start();
|
|
|
|
|
+ let reloc_end_addr_inclusive = *range.end();
|
|
|
|
|
+ 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 src_addr = bsp::memory::board_default_load_addr();
|
|
|
|
|
+
|
|
|
|
|
+ // TODO Make it work for the case src_addr > reloc_addr as well.
|
|
|
|
|
+ let diff = reloc_destination_addr as usize - src_addr as usize;
|
|
|
|
|
+ let mut current_binary_start_addr = bsp::memory::board_default_load_addr();
|
|
|
|
|
+
|
|
|
|
|
+ // Copy the whole binary.
|
|
|
|
|
+ //
|
|
|
|
|
+ // This is essentially a `memcpy()` optimized for throughput by transferring in chunks of T.
|
|
|
|
|
+ loop {
|
|
|
|
|
+ core::ptr::write_volatile(reloc_destination_addr, core::ptr::read_volatile(src_addr));
|
|
|
|
|
+ reloc_destination_addr = reloc_destination_addr.offset(1);
|
|
|
|
|
+ src_addr = src_addr.offset(1);
|
|
|
|
|
+ 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);
|
|
|
|
|
+
|
|
|
|
|
+ if reloc_destination_addr > reloc_end_addr_inclusive {
|
|
|
|
|
+ if relocated_binary_start_addr > relocated_binary_end_addr_inclusive {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let relocated_runtime_init_addr = runtime_init::runtime_init as *const () as usize + diff;
|
|
|
|
|
+ let relocated_runtime_init: fn() -> ! =
|
|
|
|
|
+ core::mem::transmute(relocated_runtime_init_addr as *const ());
|
|
|
|
|
+
|
|
|
|
|
+ relocated_runtime_init()
|
|
|
|
|
+ // The following function calls form a hack to achieve 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 this, 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.
|
|
|
|
|
+ //
|
|
|
|
|
+ // There likely is a more elegant way to do this.
|
|
|
|
|
+ let relocated_runtime_init_addr = bsp::memory::relocated_runtime_init_addr() as usize;
|
|
|
|
|
+ cpu::branch_to_raw_addr(relocated_runtime_init_addr)
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
diff -uNr 06_drivers_gpio_uart/src/runtime_init.rs 07_uart_chainloader/src/runtime_init.rs
|
|
|
|
|
--- 06_drivers_gpio_uart/src/runtime_init.rs
|
|
|
|
|
+++ 07_uart_chainloader/src/runtime_init.rs
|
|
|
|
|
@@ -17,7 +17,7 @@
|
|
|
|
|
/// - Must only be called pre `kernel_init()`.
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
unsafe fn zero_bss() {
|
|
|
|
|
- memory::zero_volatile(bsp::memory::bss_range_inclusive());
|
|
|
|
|
+ memory::zero_volatile(bsp::memory::relocated_bss_range_inclusive());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
@@ -30,6 +30,7 @@
|
|
|
|
|
/// # Safety
|
|
|
|
|
///
|
|
|
|
|
/// - Only a single core must be active and running this function.
|
|
|
|
|
+#[no_mangle]
|
|
|
|
|
pub unsafe fn runtime_init() -> ! {
|
|
|
|
|
zero_bss();
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|