#![no_std]
#![allow(clippy::needless_doctest_main)]
use banner::themes::BannerTheme;
use bitflags::bitflags;
pub mod banner;
mod patcher;
const USER_MEMORY_START: u32 = 0x0380_0000;
#[repr(u32)]
#[non_exhaustive]
pub enum ProgramType {
User = 0,
}
#[repr(u32)]
pub enum ProgramOwner {
System = 0,
Vex = 1,
Partner = 2,
}
bitflags! {
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct ProgramFlags: u32 {
const INVERT_DEFAULT_GRAPHICS = 1 << 0;
const KILL_TASKS_ON_EXIT = 1 << 1;
const THEMED_DEFAULT_GRAPHICS = 1 << 2;
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodeSignature(vex_sdk::vcodesig, [u32; 4]);
impl CodeSignature {
#[must_use]
pub const fn new(program_type: ProgramType, owner: ProgramOwner, flags: ProgramFlags) -> Self {
Self(
vex_sdk::vcodesig {
magic: vex_sdk::V5_SIG_MAGIC,
r#type: program_type as _,
owner: owner as _,
options: flags.bits(),
},
[0; 4],
)
}
}
unsafe extern "C" {
static mut __heap_start: u8;
static mut __heap_end: u8;
static mut __bss_start: u32;
static mut __bss_end: u32;
}
core::arch::global_asm!(
r#"
.section .boot, "ax"
.global _boot
_boot:
@ Load the user program stack.
@
@ This technically isn't required, as VEXos already sets up a stack for CPU1,
@ but that stack is relatively small and we have more than enough memory
@ available to us for this.
ldr sp, =__stack_top
@ Before any Rust code runs, we need to memcpy the currently running binary to
@ 0x07C00000 if a patch file is loaded into memory. See the documentation in
@ `patcher/mod.rs` for why we want to do this.
@ Check for patch magic at 0x07A00000.
mov r0, #0x07A00000
ldr r0, [r0]
ldr r1, =0xB1DF
cmp r0, r1
@ Prepare to memcpy binary to 0x07C00000
mov r0, #0x07C00000 @ memcpy dest -> r0
mov r1, #0x03800000 @ memcpy src -> r1
ldr r2, =0x07A0000C @ the length of the binary is stored at 0x07A0000C
ldr r2, [r2] @ memcpy size -> r2
@ Do the memcpy if patch magic is present (we checked this in our `cmp` instruction).
bleq __overwriter_aeabi_memcpy
@ Jump to the Rust entrypoint.
b _start
"#
);
#[inline]
#[allow(clippy::similar_names)]
#[cfg(target_vendor = "vex")]
unsafe fn zero_bss<T>(mut sbss: *mut T, ebss: *mut T)
where
T: Copy,
{
while sbss < ebss {
unsafe {
core::ptr::write_volatile(sbss, core::mem::zeroed());
sbss = sbss.offset(1);
}
}
}
#[inline]
#[allow(clippy::too_many_lines)]
pub unsafe fn startup<const BANNER: bool>(theme: BannerTheme) {
#[cfg(target_vendor = "vex")]
unsafe {
zero_bss(&raw mut __bss_start, &raw mut __bss_end);
}
#[cfg(target_vendor = "vex")]
unsafe {
vexide_core::allocator::claim(&raw mut __heap_start, &raw mut __heap_end);
}
if unsafe { vex_sdk::vexSystemLinkAddrGet() } == USER_MEMORY_START {
unsafe {
patcher::patch();
}
}
if BANNER {
banner::print(theme);
}
}