RiscV ULP boot code no longer dependent on the riscv-rt crate

This commit is contained in:
imarkov 2021-07-27 16:57:09 +03:00
parent 9fc1b78add
commit b0e5629869
10 changed files with 415 additions and 2 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
/target
**/*.rs.bk
ulp/ulp_start.o
Cargo.lock

View File

@ -1,6 +1,6 @@
[package]
name = "esp-idf-hal"
version = "0.17.0"
version = "0.17.1"
authors = ["sapir <yasapir@gmail.com>", "Ivan Markov <ivan.markov@gmail.com>"]
edition = "2018"
categories = ["embedded", "hardware-support"]

View File

@ -6,4 +6,17 @@ fn main() {
let mcu = "esp32s2";
println!("cargo:rustc-cfg={}", mcu);
#[cfg(feature = "ulp")]
{
let ulp_dir = std::env::current_dir().unwrap().join("ulp");
println!("cargo:rustc-link-search={}", ulp_dir.display());
println!("cargo:rustc-link-lib=static=ulp_start");
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed={}", ulp_dir.join("libulp_start.a").display());
println!("cargo:rerun-if-changed={}", ulp_dir.join("ulp_link.x").display());
}
}

View File

@ -8,6 +8,8 @@ mod reg;
pub mod sys;
#[cfg(feature = "ulp")]
pub mod delay;
#[cfg(feature = "ulp")]
pub mod start;
#[cfg(not(feature = "ulp"))]
#[cfg(any(esp32, esp32s2, esp32s3))]

175
src/ulp/start.rs Normal file
View File

@ -0,0 +1,175 @@
//! Minimal startup / runtime for ESP32-SXX RISC-V ULPs
//! Adapted from riscv-rt/src/lib.rs
#![deny(missing_docs)]
use super::sys::cpu;
#[export_name = "error: ulp_start appears more than once in the dependency graph"]
#[doc(hidden)]
pub static __ONCE__: () = ();
/// Rust entry point (_start_rust)
///
/// Calls main. This function never returns.
#[link_section = ".start.rust"]
#[export_name = "_start_rust"]
pub unsafe extern "C" fn start_rust() -> ! {
#[rustfmt::skip]
extern "Rust" {
// This symbol will be provided by the user
fn main();
}
cpu::rescue_from_monitor();
main();
cpu::shutdown();
}
/// Registers saved in trap handler
#[allow(missing_docs)]
#[repr(C)]
pub struct TrapFrame {
pub ra: usize,
pub t0: usize,
pub t1: usize,
pub t2: usize,
pub t3: usize,
pub t4: usize,
pub t5: usize,
pub t6: usize,
pub a0: usize,
pub a1: usize,
pub a2: usize,
pub a3: usize,
pub a4: usize,
pub a5: usize,
pub a6: usize,
pub a7: usize,
}
/// Trap entry point rust (_start_trap_rust)
///
/// `mcause` is read to determine the cause of the trap. XLEN-1 bit indicates
/// if it's an interrupt or an exception. The result is examined and ExceptionHandler
/// or one of the core interrupt handlers is called.
#[link_section = ".trap.rust"]
#[export_name = "_start_trap_rust"]
pub extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
// use riscv::register::mcause;
extern "C" {
fn ExceptionHandler(trap_frame: &TrapFrame);
#[allow(dead_code)]
fn DefaultHandler();
}
unsafe {
// let cause = mcause::read();
// if cause.is_exception() {
ExceptionHandler(&*trap_frame)
// } else {
// let code = cause.code();
// if code < __INTERRUPTS.len() {
// let h = &__INTERRUPTS[code];
// if h.reserved == 0 {
// DefaultHandler();
// } else {
// (h.handler)();
// }
// } else {
// DefaultHandler();
// }
// }
}
}
#[doc(hidden)]
#[no_mangle]
#[allow(unused_variables, non_snake_case)]
pub fn DefaultExceptionHandler(trap_frame: &TrapFrame) -> ! {
loop {
// Prevent this from turning into a UDF instruction
// see rust-lang/rust#28728 for details
continue;
}
}
#[doc(hidden)]
#[no_mangle]
#[allow(unused_variables, non_snake_case)]
pub fn DefaultInterruptHandler() {
loop {
// Prevent this from turning into a UDF instruction
// see rust-lang/rust#28728 for details
continue;
}
}
/* Interrupts */
#[doc(hidden)]
pub enum Interrupt {
UserSoft,
SupervisorSoft,
MachineSoft,
UserTimer,
SupervisorTimer,
MachineTimer,
UserExternal,
SupervisorExternal,
MachineExternal,
}
pub use self::Interrupt as interrupt;
extern "C" {
fn UserSoft();
fn SupervisorSoft();
fn MachineSoft();
fn UserTimer();
fn SupervisorTimer();
fn MachineTimer();
fn UserExternal();
fn SupervisorExternal();
fn MachineExternal();
}
#[doc(hidden)]
pub union Vector {
handler: unsafe extern "C" fn(),
reserved: usize,
}
#[doc(hidden)]
#[allow(dead_code)]
#[no_mangle]
pub static __INTERRUPTS: [Vector; 12] = [
Vector { handler: UserSoft },
Vector {
handler: SupervisorSoft,
},
Vector { reserved: 0 },
Vector {
handler: MachineSoft,
},
Vector { handler: UserTimer },
Vector {
handler: SupervisorTimer,
},
Vector { reserved: 0 },
Vector {
handler: MachineTimer,
},
Vector {
handler: UserExternal,
},
Vector {
handler: SupervisorExternal,
},
Vector { reserved: 0 },
Vector {
handler: MachineExternal,
},
];

BIN
ulp/libulp_start.a Normal file

Binary file not shown.

88
ulp/ulp_link.x Normal file
View File

@ -0,0 +1,88 @@
PROVIDE(_ram_size = 2K);
PROVIDE(UserSoft = DefaultHandler);
PROVIDE(SupervisorSoft = DefaultHandler);
PROVIDE(MachineSoft = DefaultHandler);
PROVIDE(UserTimer = DefaultHandler);
PROVIDE(SupervisorTimer = DefaultHandler);
PROVIDE(MachineTimer = DefaultHandler);
PROVIDE(UserExternal = DefaultHandler);
PROVIDE(SupervisorExternal = DefaultHandler);
PROVIDE(MachineExternal = DefaultHandler);
PROVIDE(DefaultHandler = DefaultInterruptHandler);
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
ENTRY(reset_vector)
MEMORY
{
ram(RW) : ORIGIN = 0, LENGTH = _ram_size
}
PROVIDE(_stext = ORIGIN(ram));
SECTIONS
{
.text.dummy (NOLOAD) :
{
/* This section is intended to make _stext address work */
. = ABSOLUTE(_stext);
} > ram
.text _stext :
{
KEEP(*(.init)); // Default reset vector must link to offset 0x0
KEEP(*(.start.rust));
KEEP(*(.trap.rust));
*(.text .text.*);
} > ram
.rodata ALIGN(4):
{
*(.srodata .srodata.*);
*(.rodata .rodata.*);
/* 4-byte align the end (VMA) of this section.
This is required by LLD to ensure the LMA of the following .data
section will have the correct alignment. */
. = ALIGN(4);
} > ram
.data ALIGN(4):
{
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.* .sdata2 .sdata2.*);
*(.data .data.*);
. = ALIGN(4);
} > ram
.bss ALIGN(4) :
{
*(.sbss .sbss.* .bss .bss.*);
. = ALIGN(4);
} > ram
/* fake output .got section */
/* Dynamic relocations are unsupported. This section is only used to detect
relocatable code in the input files and raise an error if relocatable code
is found */
.got (INFO) :
{
KEEP(*(.got .got.*));
}
.eh_frame (INFO) :
{
KEEP(*(.eh_frame))
}
.eh_frame_hdr (INFO) :
{
*(.eh_frame_hdr)
}
_stack_top = ORIGIN(ram) + LENGTH(ram);
}

117
ulp/ulp_start.S Normal file
View File

@ -0,0 +1,117 @@
// NOTE: Adapted from riscv-rt/asm.S
#define REGBYTES (1 << 2)
.section .init, "ax"
.global reset_vector
.global irq_vector
// The reset vector, jumps to startup code
reset_vector:
j _start
// Interrupt handler
.option push
.option norelax // To prevent an unsupported R_RISCV_ALIGN relocation from being generated
.balign 16
irq_vector:
addi sp, sp, -16*REGBYTES
sw ra, 0*REGBYTES(sp)
sw t0, 1*REGBYTES(sp)
sw t1, 2*REGBYTES(sp)
sw t2, 3*REGBYTES(sp)
sw t3, 4*REGBYTES(sp)
sw t4, 5*REGBYTES(sp)
sw t5, 6*REGBYTES(sp)
sw t6, 7*REGBYTES(sp)
sw a0, 8*REGBYTES(sp)
sw a1, 9*REGBYTES(sp)
sw a2, 10*REGBYTES(sp)
sw a3, 11*REGBYTES(sp)
sw a4, 12*REGBYTES(sp)
sw a5, 13*REGBYTES(sp)
sw a6, 14*REGBYTES(sp)
sw a7, 15*REGBYTES(sp)
add a0, sp, zero
jal ra, _start_trap_rust
lw ra, 0*REGBYTES(sp)
lw t0, 1*REGBYTES(sp)
lw t1, 2*REGBYTES(sp)
lw t2, 3*REGBYTES(sp)
lw t3, 4*REGBYTES(sp)
lw t4, 5*REGBYTES(sp)
lw t5, 6*REGBYTES(sp)
lw t6, 7*REGBYTES(sp)
lw a0, 8*REGBYTES(sp)
lw a1, 9*REGBYTES(sp)
lw a2, 10*REGBYTES(sp)
lw a3, 11*REGBYTES(sp)
lw a4, 12*REGBYTES(sp)
lw a5, 13*REGBYTES(sp)
lw a6, 14*REGBYTES(sp)
lw a7, 15*REGBYTES(sp)
addi sp, sp, 16*REGBYTES
ret
.option pop
_start:
.cfi_startproc
.cfi_undefined ra
li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
li x10,0
li x11,0
li x12,0
li x13,0
li x14,0
li x15,0
li x16,0
li x17,0
li x18,0
li x19,0
li x20,0
li x21,0
li x22,0
li x23,0
li x24,0
li x25,0
li x26,0
li x27,0
li x28,0
li x29,0
li x30,0
li x31,0
.option push
.option norelax // To prevent an unsupported R_RISCV_ALIGN relocation from being generated
la gp, __global_pointer$
.option pop
// Allocate stack
la sp, _stack_top
// Set frame pointer
add s0, sp, zero
jal zero, _start_rust
.cfi_endproc
loop:
j loop
// Make sure there is an abort when linking
.globl abort
abort:
j abort

View File

@ -0,0 +1,7 @@
# remove existing blob because otherwise this will append object file to the old blob
Remove-Item -Force ulp_start.a
riscv32-esp-elf-gcc -Desp_ulp -ggdb3 -fdebug-prefix-map=$(pwd)=/ulp_start -c -mabi=ilp32 -march=rv32imc ulp_start.S -o ulp_start.o
riscv32-esp-elf-ar crs libulp_start.a ulp_start.o
Remove-Item ulp_start.o

11
ulp/ulp_start_assemble.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
set -euxo pipefail
# remove existing blob because otherwise this will append object file to the old blob
rm -f ulp_start.a
riscv32-esp-elf-gcc -Desp_ulp -ggdb3 -fdebug-prefix-map=$(pwd)=/ulp_start -c -mabi=ilp32 -march=rv32imc ulp_start.S -o ulp_start.o
riscv32-esp-elf-ar crs libulp_start.a ulp_start.o
rm ulp_start.o