feat: ✨ Add chainboot boot loader
This commit is contained in:
parent
3c57c6e2df
commit
cfe4a230de
|
@ -20,6 +20,23 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chainboot"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cortex-a",
|
||||
"machine",
|
||||
"r0",
|
||||
"seahash",
|
||||
"snafu",
|
||||
"tock-registers",
|
||||
"usize_conversions",
|
||||
"ux",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-a"
|
||||
version = "7.0.0"
|
||||
|
@ -106,6 +123,12 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "snafu"
|
||||
version = "0.7.0"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"nucleus"
|
||||
"nucleus",
|
||||
"bin/chainboot"
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
|
|
21
Justfile
21
Justfile
|
@ -6,6 +6,13 @@ zellij:
|
|||
cargo make zellij-nucleus
|
||||
zellij --layout-path emulation/layout.zellij
|
||||
|
||||
# Build and run chainboot in QEMU with serial port emulation
|
||||
zellij-cb:
|
||||
# Connect to it via chainofcommand to load an actual kernel
|
||||
# TODO: actually run chainofcommand in a zellij session too
|
||||
cargo make zellij-cb
|
||||
zellij --layout-path emulation/layout.zellij
|
||||
|
||||
# Build and run kernel in QEMU
|
||||
qemu:
|
||||
cargo make qemu
|
||||
|
@ -14,6 +21,11 @@ qemu:
|
|||
qemu-gdb:
|
||||
cargo make qemu-gdb
|
||||
|
||||
# Build and run chainboot in QEMU
|
||||
qemu-cb:
|
||||
# Connect to it via chainofcommand to load an actual kernel
|
||||
cargo make qemu-cb
|
||||
|
||||
# Build and write kernel to an SD Card
|
||||
device:
|
||||
cargo make sdcard
|
||||
|
@ -22,6 +34,11 @@ device:
|
|||
device-eject:
|
||||
cargo make sdeject
|
||||
|
||||
# Build and write chainboot to an SD Card, then eject the SD Card volume
|
||||
cb-eject:
|
||||
cd bin/chainboot
|
||||
cargo make cb-eject
|
||||
|
||||
# Build default hw kernel
|
||||
build:
|
||||
cargo make build
|
||||
|
@ -61,6 +78,10 @@ openocd:
|
|||
gdb:
|
||||
cargo make gdb
|
||||
|
||||
# Build and run chainboot in GDB using openocd or QEMU as target (gdb port 5555)
|
||||
gdb-cb:
|
||||
cargo make gdb-cb
|
||||
|
||||
# Build and print all symbols in the kernel
|
||||
nm:
|
||||
cargo make nm
|
||||
|
|
|
@ -95,6 +95,13 @@ env = { "TARGET_FEATURES" = "${QEMU_FEATURES}" }
|
|||
command = "cargo"
|
||||
args = ["build", "@@split(PLATFORM_TARGET, )", "--release"]
|
||||
|
||||
[tasks.qemu-runner]
|
||||
dependencies = ["build-qemu", "kernel-binary"]
|
||||
env = { "TARGET_FEATURES" = "${QEMU_FEATURES}" }
|
||||
script = [
|
||||
"${QEMU} ${QEMU_OPTS} ${QEMU_RUNNER_OPTS} -dtb ${TARGET_DTB} -kernel ${KERNEL_BIN}"
|
||||
]
|
||||
|
||||
[tasks.expand]
|
||||
env = { "TARGET_FEATURES" = "" }
|
||||
command = "cargo"
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
[package]
|
||||
name = "chainboot"
|
||||
version = "0.0.1"
|
||||
authors = ["Berkus Decker <berkus+vesper@metta.systems>"]
|
||||
description = "Chain boot loader"
|
||||
license = "BlueOak-1.0.0"
|
||||
categories = ["no-std", "embedded", "os"]
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "experimental" }
|
||||
|
||||
[features]
|
||||
default = ["asm"]
|
||||
# Build for running under QEMU with semihosting, so various halt/reboot options would for example quit QEMU instead.
|
||||
qemu = ["machine/qemu"]
|
||||
# Build for debugging it over JTAG/SWD connection - halts on first non-startup function start.
|
||||
jtag = ["machine/jtag"]
|
||||
# Dummy feature, ignored in this crate.
|
||||
noserial = []
|
||||
# Startup relocation code is implemented in assembly
|
||||
asm = []
|
||||
# Mutually exclusive features to choose a target board
|
||||
rpi3 = ["machine/rpi3"]
|
||||
rpi4 = ["machine/rpi4"]
|
||||
|
||||
[dependencies]
|
||||
machine = { path = "../../machine" }
|
||||
r0 = "1.0"
|
||||
cortex-a = "7.0"
|
||||
tock-registers = "0.7"
|
||||
ux = { version = "0.1", default-features = false }
|
||||
usize_conversions = "0.2"
|
||||
bit_field = "0.10"
|
||||
bitflags = "1.3"
|
||||
cfg-if = "1.0"
|
||||
snafu = { version = "0.7", default-features = false }
|
||||
seahash = "4.1"
|
|
@ -0,0 +1,52 @@
|
|||
[env]
|
||||
CHAINBOOT_ELF = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/${TARGET}/release/chainboot"
|
||||
CHAINBOOT_BIN = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/chainboot.bin"
|
||||
|
||||
[tasks.kernel-binary]
|
||||
env = { "BINARY_FILE" = "${CHAINBOOT_ELF}" }
|
||||
run_task = "custom-binary"
|
||||
|
||||
[tasks.hopper]
|
||||
disabled = true
|
||||
|
||||
[tasks.zellij-nucleus]
|
||||
disabled = true
|
||||
|
||||
[tasks.zellij-cb]
|
||||
env = { "KERNEL_BIN" = "${CHAINBOOT_BIN}", "QEMU_OPTS" = "${QEMU_OPTS} ${QEMU_DISASM_OPTS}" }
|
||||
run_task = "zellij-config"
|
||||
|
||||
[tasks.zellij-cb-gdb]
|
||||
env = { "KERNEL_BIN" = "${CHAINBOOT_BIN}", "QEMU_OPTS" = "${QEMU_OPTS} ${QEMU_DISASM_OPTS} ${QEMU_GDB_OPTS}", "TARGET_BOARD" = "rpi3", "TARGET_DTB" = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/bcm2710-rpi-3-b-plus.dtb" }
|
||||
run_task = "zellij-config"
|
||||
|
||||
[tasks.qemu]
|
||||
disabled = true
|
||||
|
||||
[tasks.qemu-cb]
|
||||
env = { "QEMU_RUNNER_OPTS" = "${QEMU_SERIAL_OPTS}", "KERNEL_BIN" = "${CHAINBOOT_BIN}", "TARGET_DTB" = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/bcm2710-rpi-3-b-plus.dtb" }
|
||||
extend = "qemu-runner"
|
||||
|
||||
[tasks.gdb]
|
||||
disabled = true
|
||||
|
||||
[tasks.gdb-cb]
|
||||
dependencies = ["build", "kernel-binary", "gdb-config"]
|
||||
env = { "RUST_GDB" = "${GDB}" }
|
||||
script = [
|
||||
"rust-gdb -x ${GDB_CONNECT_FILE} ${CHAINBOOT_ELF}"
|
||||
]
|
||||
|
||||
[tasks.sdcard]
|
||||
dependencies = ["build", "kernel-binary"]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
'''
|
||||
kernelImage = set "chain_boot_rpi4.img"
|
||||
cp ${CHAINBOOT_BIN} ${VOLUME}/${kernelImage}
|
||||
echo "Copied chainboot to ${VOLUME}/${kernelImage}"
|
||||
'''
|
||||
]
|
||||
|
||||
[tasks.cb-eject]
|
||||
dependencies = ["sdeject"]
|
|
@ -0,0 +1,6 @@
|
|||
const LINKER_SCRIPT: &str = "bin/chainboot/src/link.ld";
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed={}", LINKER_SCRIPT);
|
||||
println!("cargo:rustc-link-arg=--script={}", LINKER_SCRIPT);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// Assembly counterpart to this file.
|
||||
#[cfg(feature = "asm")]
|
||||
core::arch::global_asm!(include_str!("boot.s"));
|
||||
|
||||
// This is quite impossible - the linker constants are resolved to fully constant offsets in asm
|
||||
// version, but are image-relative symbols in rust, and I see no way to force it otherwise.
|
||||
#[no_mangle]
|
||||
#[link_section = ".text._start"]
|
||||
#[cfg(not(feature = "asm"))]
|
||||
pub unsafe extern "C" fn _start() -> ! {
|
||||
use {
|
||||
cortex_a::registers::{MPIDR_EL1, SP},
|
||||
machine::endless_sleep,
|
||||
tock_registers::interfaces::{Readable, Writeable},
|
||||
};
|
||||
|
||||
const CORE_0: u64 = 0;
|
||||
const CORE_MASK: u64 = 0x3;
|
||||
|
||||
if CORE_0 == MPIDR_EL1.get() & CORE_MASK {
|
||||
// if not core0, infinitely wait for events
|
||||
endless_sleep()
|
||||
}
|
||||
|
||||
// These are a problem, because they are not interpreted as constants here.
|
||||
// Subsequently, this code tries to read values from not-yet-existing data locations.
|
||||
extern "C" {
|
||||
// Boundaries of the .bss section, provided by the linker script
|
||||
static mut __bss_start: u64;
|
||||
static mut __bss_end_exclusive: u64;
|
||||
// Load address of the kernel binary
|
||||
static mut __binary_nonzero_lma: u64;
|
||||
// Address to relocate to and image size
|
||||
static mut __binary_nonzero_vma: u64;
|
||||
static mut __binary_nonzero_vma_end_exclusive: u64;
|
||||
// Stack top
|
||||
static mut __boot_core_stack_end_exclusive: u64;
|
||||
}
|
||||
|
||||
// Set stack pointer.
|
||||
SP.set(&mut __boot_core_stack_end_exclusive as *mut u64 as u64);
|
||||
|
||||
// Zeroes the .bss section
|
||||
r0::zero_bss(&mut __bss_start, &mut __bss_end_exclusive);
|
||||
|
||||
// Relocate the code
|
||||
core::ptr::copy_nonoverlapping(
|
||||
&mut __binary_nonzero_lma as *const u64,
|
||||
&mut __binary_nonzero_vma as *mut u64,
|
||||
(&mut __binary_nonzero_vma_end_exclusive as *mut u64 as u64
|
||||
- &mut __binary_nonzero_vma as *mut u64 as u64) as usize,
|
||||
);
|
||||
|
||||
_start_rust();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Public Code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
/// The Rust entry of the `kernel` binary.
|
||||
///
|
||||
/// The function is called from the assembly `_start` function, keep it to support "asm" feature.
|
||||
#[no_mangle]
|
||||
pub unsafe fn _start_rust(max_kernel_size: u64) -> ! {
|
||||
crate::kernel_init(max_kernel_size)
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
//
|
||||
// Copyright (c) 2021 Andre Richter <andre.o.richter@gmail.com>
|
||||
// Modifications
|
||||
// Copyright (c) 2021- Berkus <berkus+github@metta.systems>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Load the address of a symbol into a register, PC-relative.
|
||||
//
|
||||
// The symbol must lie within +/- 4 GiB of the Program Counter.
|
||||
//
|
||||
// # Resources
|
||||
//
|
||||
// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html
|
||||
.macro ADR_REL register, symbol
|
||||
adrp \register, \symbol
|
||||
add \register, \register, #:lo12:\symbol
|
||||
.endm
|
||||
|
||||
// Load the address of a symbol into a register, absolute.
|
||||
//
|
||||
// # Resources
|
||||
//
|
||||
// - https://sourceware.org/binutils/docs-2.36/as/AArch64_002dRelocations.html
|
||||
.macro ADR_ABS register, symbol
|
||||
movz \register, #:abs_g2:\symbol
|
||||
movk \register, #:abs_g1_nc:\symbol
|
||||
movk \register, #:abs_g0_nc:\symbol
|
||||
.endm
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Public Code
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
.section .text._start
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// fn _start()
|
||||
//------------------------------------------------------------------------------
|
||||
_start:
|
||||
// Only proceed on the boot core. Park it otherwise.
|
||||
mrs x1, MPIDR_EL1
|
||||
and x1, x1, 0b11 // core id mask
|
||||
cmp x1, 0 // boot core id
|
||||
b.ne .L_parking_loop
|
||||
|
||||
// If execution reaches here, it is the boot core.
|
||||
|
||||
// Initialize bss.
|
||||
ADR_ABS x0, __bss_start
|
||||
ADR_ABS x1, __bss_end_exclusive
|
||||
|
||||
.L_bss_init_loop:
|
||||
cmp x0, x1
|
||||
b.eq .L_relocate_binary
|
||||
stp xzr, xzr, [x0], #16
|
||||
b .L_bss_init_loop
|
||||
|
||||
// Next, relocate the binary.
|
||||
.L_relocate_binary:
|
||||
ADR_REL x0, __binary_nonzero_lma // The address the binary got loaded to.
|
||||
ADR_ABS x1, __binary_nonzero_vma // The address the binary was linked to.
|
||||
ADR_ABS x2, __binary_nonzero_vma_end_exclusive
|
||||
sub x4, x1, x0 // Get difference between vma and lma as max size
|
||||
|
||||
.L_copy_loop:
|
||||
ldr x3, [x0], #8
|
||||
str x3, [x1], #8
|
||||
cmp x1, x2
|
||||
b.lo .L_copy_loop
|
||||
|
||||
// Prepare the jump to Rust code.
|
||||
// Set the stack pointer.
|
||||
ADR_ABS x0, __rpi_phys_binary_load_addr
|
||||
mov sp, x0
|
||||
|
||||
// Pass maximum kernel size as an argument to Rust init function.
|
||||
mov x0, x4
|
||||
|
||||
// Jump to the relocated Rust code.
|
||||
ADR_ABS x1, _start_rust
|
||||
br x1
|
||||
|
||||
// Infinitely wait for events (aka "park the core").
|
||||
.L_parking_loop:
|
||||
wfe
|
||||
b .L_parking_loop
|
||||
|
||||
.size _start, . - _start
|
||||
.type _start, function
|
||||
.global _start
|
|
@ -0,0 +1,98 @@
|
|||
/* SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
|
||||
* Copyright (c) 2021- Berkus <berkus+github@metta.systems>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information from:
|
||||
* [Output Section Address](https://sourceware.org/binutils/docs/ld/Output-Section-Address.html)
|
||||
* [Output Section LMA](https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html)
|
||||
* [Output Section Attributes](https://sourceware.org/binutils/docs/ld/Output-Section-Attributes.html#Output-Section-Attributes)
|
||||
*/
|
||||
|
||||
/* The physical address at which the the kernel binary will be loaded by the Raspberry's firmware */
|
||||
__rpi_phys_binary_load_addr = 0x80000;
|
||||
|
||||
|
||||
ENTRY(__rpi_phys_binary_load_addr)
|
||||
|
||||
/* Flags:
|
||||
* 4 == R
|
||||
* 5 == RX
|
||||
* 6 == RW
|
||||
*
|
||||
* Segments are marked PT_LOAD below so that the ELF file provides virtual and physical addresses.
|
||||
* It doesn't mean all of them need actually be loaded.
|
||||
*/
|
||||
PHDRS
|
||||
{
|
||||
segment_boot_core_stack PT_LOAD FLAGS(6);
|
||||
segment_start_code PT_LOAD FLAGS(5);
|
||||
segment_code PT_LOAD FLAGS(5);
|
||||
segment_data PT_LOAD FLAGS(6);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/***********************************************************************************************
|
||||
* Boot Core Stack
|
||||
***********************************************************************************************/
|
||||
.boot_core_stack (NOLOAD) :
|
||||
{
|
||||
/* ^ */
|
||||
/* | stack */
|
||||
. += __rpi_phys_binary_load_addr; /* | growth */
|
||||
/* | direction */
|
||||
__boot_core_stack_end_exclusive = .; /* | */
|
||||
} :segment_boot_core_stack
|
||||
|
||||
. = __rpi_phys_binary_load_addr;
|
||||
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.text._start))
|
||||
/* *(text.memcpy) -- only relevant for Rust relocator impl which is currently impossible */
|
||||
} :segment_start_code
|
||||
|
||||
/* Align to 8 bytes, b/c relocating the binary is done in u64 chunks */
|
||||
. = ALIGN(8);
|
||||
|
||||
__binary_nonzero_lma = .;
|
||||
|
||||
/* Set the link address to 32 MiB */
|
||||
/* This dictates the max size of the loadable kernel. */
|
||||
. += 0x2000000;
|
||||
|
||||
/***********************************************************************************************
|
||||
* Code + RO Data + Global Offset Table
|
||||
***********************************************************************************************/
|
||||
__binary_nonzero_vma = .;
|
||||
.text : AT (ADDR(.text) + SIZEOF(.text))
|
||||
{
|
||||
*(.text._start_rust) /* The Rust entry point */
|
||||
/* *(text.memcpy) -- only relevant for Rust relocator impl which is currently impossible */
|
||||
*(.text*) /* Everything else */
|
||||
} :segment_code
|
||||
|
||||
.rodata : ALIGN(8) { *(.rodata*) } :segment_code
|
||||
.got : ALIGN(8) { *(.got) } :segment_code
|
||||
|
||||
/***********************************************************************************************
|
||||
* Data + BSS
|
||||
***********************************************************************************************/
|
||||
.data : { *(.data*) } :segment_data
|
||||
|
||||
/* Fill up to 8 bytes, b/c relocating the binary is done in u64 chunks */
|
||||
. = ALIGN(8);
|
||||
__binary_nonzero_vma_end_exclusive = .;
|
||||
|
||||
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
|
||||
.bss (NOLOAD) : ALIGN(16)
|
||||
{
|
||||
__bss_start = .;
|
||||
*(.bss*);
|
||||
. = ALIGN(16);
|
||||
__bss_end_exclusive = .;
|
||||
} :segment_data
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
// Based on miniload by @andre-richter
|
||||
#![feature(format_args_nl)]
|
||||
#![feature(custom_test_frameworks)]
|
||||
#![test_runner(machine::tests::test_runner)]
|
||||
#![reexport_test_harness_main = "test_main"]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use {
|
||||
core::{hash::Hasher, panic::PanicInfo},
|
||||
cortex_a::asm::barrier,
|
||||
machine::{
|
||||
devices::SerialOps,
|
||||
platform::rpi3::{gpio::GPIO, pl011_uart::PL011Uart, BcmHost},
|
||||
print, println, CONSOLE,
|
||||
},
|
||||
seahash::SeaHasher,
|
||||
};
|
||||
|
||||
mod boot;
|
||||
|
||||
/// Early init code.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Only a single core must be active and running this function.
|
||||
/// - The init calls in this function must appear in the correct order.
|
||||
unsafe fn kernel_init(max_kernel_size: u64) -> ! {
|
||||
#[cfg(feature = "jtag")]
|
||||
machine::arch::jtag::wait_debugger();
|
||||
|
||||
let gpio = GPIO::default();
|
||||
let uart = PL011Uart::default();
|
||||
let uart = uart.prepare(&gpio).expect("What could go wrong?");
|
||||
CONSOLE.lock(|c| {
|
||||
// Move uart into the global CONSOLE.
|
||||
c.replace_with(uart.into());
|
||||
});
|
||||
|
||||
// println! is usable from here on.
|
||||
|
||||
// Transition from unsafe to safe.
|
||||
kernel_main(max_kernel_size)
|
||||
}
|
||||
|
||||
// https://onlineasciitools.com/convert-text-to-ascii-art (FIGlet) with `cricket` font
|
||||
const LOGO: &str = r#"
|
||||
__ __ __ __
|
||||
.----| |--.---.-|__.-----| |--.-----.-----| |_
|
||||
| __| | _ | | | _ | _ | _ | _|
|
||||
|____|__|__|___._|__|__|__|_____|_____|_____|____|
|
||||
"#;
|
||||
|
||||
fn read_u64() -> u64 {
|
||||
CONSOLE.lock(|c| {
|
||||
let mut val: u64 = u64::from(c.read_byte());
|
||||
val |= u64::from(c.read_byte()) << 8;
|
||||
val |= u64::from(c.read_byte()) << 16;
|
||||
val |= u64::from(c.read_byte()) << 24;
|
||||
val |= u64::from(c.read_byte()) << 32;
|
||||
val |= u64::from(c.read_byte()) << 40;
|
||||
val |= u64::from(c.read_byte()) << 48;
|
||||
val |= u64::from(c.read_byte()) << 56;
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
/// The main function running after the early init.
|
||||
fn kernel_main(max_kernel_size: u64) -> ! {
|
||||
#[cfg(test)]
|
||||
test_main();
|
||||
|
||||
print!("{}", LOGO);
|
||||
println!("{:>51}\n", BcmHost::board_name());
|
||||
println!("[<<] Requesting kernel image...");
|
||||
|
||||
let kernel_addr: *mut u8 = BcmHost::kernel_load_address() as *mut u8;
|
||||
|
||||
loop {
|
||||
CONSOLE.lock(|c| c.flush());
|
||||
|
||||
// Discard any spurious received characters before starting with the loader protocol.
|
||||
CONSOLE.lock(|c| c.clear_rx());
|
||||
|
||||
// Notify `chainofcommand` to send the binary.
|
||||
for _ in 0..3 {
|
||||
CONSOLE.lock(|c| c.write_byte(3u8));
|
||||
}
|
||||
|
||||
// Read the binary's size.
|
||||
let size = read_u64();
|
||||
|
||||
// Check the size to fit RAM
|
||||
if size > max_kernel_size {
|
||||
println!("ERR Kernel image too big (over {} bytes)", max_kernel_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
print!("OK");
|
||||
|
||||
// We use seahash, simple and with no_std implementation.
|
||||
let mut hasher = SeaHasher::new();
|
||||
|
||||
// Read the kernel byte by byte.
|
||||
for i in 0..size {
|
||||
let val = CONSOLE.lock(|c| c.read_byte());
|
||||
unsafe {
|
||||
core::ptr::write_volatile(kernel_addr.offset(i as isize), val);
|
||||
}
|
||||
let written = unsafe { core::ptr::read_volatile(kernel_addr.offset(i as isize)) };
|
||||
hasher.write_u8(written);
|
||||
}
|
||||
|
||||
// Read the binary's checksum.
|
||||
let checksum = read_u64();
|
||||
|
||||
let valid = hasher.finish() == checksum;
|
||||
if !valid {
|
||||
println!("ERR Kernel image checksum mismatch");
|
||||
continue;
|
||||
}
|
||||
|
||||
print!("OK");
|
||||
break;
|
||||
}
|
||||
|
||||
println!(
|
||||
"[<<] Loaded! Executing the payload now from {:p}\n",
|
||||
kernel_addr
|
||||
);
|
||||
CONSOLE.lock(|c| c.flush());
|
||||
|
||||
// Use black magic to create a function pointer.
|
||||
let kernel: fn() -> ! = unsafe { core::mem::transmute(kernel_addr) };
|
||||
|
||||
// Force everything to complete before we jump.
|
||||
unsafe { barrier::isb(barrier::SY) };
|
||||
|
||||
// Jump to loaded kernel!
|
||||
kernel()
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panicked(info: &PanicInfo) -> ! {
|
||||
machine::panic::handler(info)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[panic_handler]
|
||||
fn panicked(info: &PanicInfo) -> ! {
|
||||
machine::panic::handler_for_tests(info)
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
name = "machine"
|
||||
version = "0.0.1"
|
||||
authors = ["Berkus Decker <berkus+vesper@metta.systems>"]
|
||||
description = "Vesper nanokernel shared code library."
|
||||
description = "Vesper nanokernel shared code library, useful also for the chainboot loader."
|
||||
documentation = "https://docs.metta.systems/vesper"
|
||||
homepage = "https://github.com/metta-systems/vesper"
|
||||
repository = "https://github.com/metta-systems/vesper"
|
||||
|
|
|
@ -7,25 +7,27 @@
|
|||
env = { "BINARY_FILE" = "${KERNEL_ELF}" }
|
||||
run_task = "custom-binary"
|
||||
|
||||
[tasks.qemu-runner]
|
||||
dependencies = ["build-qemu", "kernel-binary"]
|
||||
env = { "TARGET_FEATURES" = "${QEMU_FEATURES}" }
|
||||
script = [
|
||||
"${QEMU} ${QEMU_OPTS} ${QEMU_RUNNER_OPTS} -dtb ${TARGET_DTB} -kernel ${KERNEL_BIN}"
|
||||
]
|
||||
|
||||
[tasks.qemu]
|
||||
extend = "qemu-runner"
|
||||
env = { "QEMU_RUNNER_OPTS" = "${QEMU_SERIAL_OPTS}", "TARGET_DTB" = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/bcm2710-rpi-3-b-plus.dtb" }
|
||||
extend = "qemu-runner"
|
||||
|
||||
[tasks.qemu-cb]
|
||||
disabled = true
|
||||
|
||||
[tasks.qemu-gdb]
|
||||
extend = "qemu-runner"
|
||||
env = { "QEMU_RUNNER_OPTS" = "${QEMU_SERIAL_OPTS} ${QEMU_GDB_OPTS}", "TARGET_DTB" = "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/targets/bcm2710-rpi-3-b-plus.dtb" }
|
||||
extend = "qemu-runner"
|
||||
|
||||
[tasks.zellij-nucleus]
|
||||
env = { "KERNEL_BIN" = "${KERNEL_BIN}" }
|
||||
run_task = "zellij-config"
|
||||
|
||||
[tasks.zellij-cb]
|
||||
disabled = true
|
||||
|
||||
[tasks.zellij-cb-gdb]
|
||||
disabled = true
|
||||
|
||||
[tasks.gdb-config]
|
||||
script_runner = "@duckscript"
|
||||
script = [
|
||||
|
@ -44,6 +46,9 @@ script = [
|
|||
"rust-gdb -x ${GDB_CONNECT_FILE} ${KERNEL_ELF}"
|
||||
]
|
||||
|
||||
[tasks.gdb-cb]
|
||||
disabled = true
|
||||
|
||||
[tasks.nm]
|
||||
dependencies = ["build", "kernel-binary"]
|
||||
script = [
|
||||
|
@ -62,6 +67,9 @@ script = [
|
|||
'''
|
||||
]
|
||||
|
||||
[tasks.cb-eject]
|
||||
disabled = true
|
||||
|
||||
[tasks.hopper]
|
||||
dependencies = ["build", "kernel-binary"]
|
||||
# The cmd line below causes a bug in hopper, see https://www.dropbox.com/s/zyw5mfx0bepcjb1/hopperv4-RAW-bug.mov?dl=0
|
||||
|
|
Loading…
Reference in New Issue