Skip to main content

sel4_reset/
lib.rs

1//
2// Copyright 2024, Colias Group, LLC
3//
4// SPDX-License-Identifier: BSD-2-Clause
5//
6
7#![no_std]
8
9use core::arch::global_asm;
10use core::ptr;
11use core::slice;
12
13use sel4_stack::{Stack, StackBottom};
14
15#[cfg(not(any(target_arch = "aarch64",)))]
16compile_error!("unsupported architecture");
17
18// // //
19
20#[repr(C)]
21#[derive(Debug)]
22struct RegionMeta {
23    vaddr: usize,
24    offset: usize,
25    filesz: usize,
26    memsz: usize,
27}
28
29struct Regions<'a> {
30    meta: &'a [RegionMeta],
31    data: &'a [u8],
32}
33
34impl Regions<'_> {
35    unsafe fn reset_memory(&self) {
36        for meta in self.meta {
37            let dst = unsafe { slice::from_raw_parts_mut(meta.vaddr as *mut _, meta.memsz) };
38            let (dst_data, dst_zero) = dst.split_at_mut(meta.filesz);
39            let src_data = &self.data[meta.offset..][..meta.filesz];
40            dst_data.copy_from_slice(src_data);
41            unsafe {
42                ptr::write_bytes(dst_zero.as_mut_ptr(), 0, dst_zero.len());
43            }
44        }
45    }
46}
47
48// // //
49
50const STACK_SIZE: usize = 4096;
51
52#[unsafe(link_section = ".persistent")]
53static STACK: Stack<STACK_SIZE> = Stack::new();
54
55#[unsafe(no_mangle)]
56static __sel4_reset__stack_bottom: StackBottom = STACK.bottom();
57
58// // //
59
60#[unsafe(no_mangle)]
61unsafe extern "C" fn __sel4_reset__reset_memory() {
62    unsafe {
63        get_regions().reset_memory();
64    }
65}
66
67unsafe fn get_regions() -> Regions<'static> {
68    unsafe {
69        Regions {
70            meta: slice::from_raw_parts(
71                (sel4_reset_regions_start + sel4_reset_regions_meta_offset) as *const _,
72                sel4_reset_regions_meta_count,
73            ),
74            data: slice::from_raw_parts(
75                (sel4_reset_regions_start + sel4_reset_regions_data_offset) as *const _,
76                sel4_reset_regions_data_size,
77            ),
78        }
79    }
80}
81
82// HACK to force variables into .rodata without causing .rodata to end up in a PF_W segment
83macro_rules! rodata {
84    ($ident:ident) => {
85        unsafe extern "C" {
86            static $ident: usize;
87        }
88        global_asm! {
89            r#"
90                .section .rodata
91                .global {ident}
92                {ident}:
93            "#,
94            #[cfg(target_pointer_width = "64")]
95            r#"
96                    .quad 0
97            "#,
98            #[cfg(target_pointer_width = "32")]
99            r#"
100                    .word 0
101            "#,
102            r#"
103                .size {ident}, .-{ident}
104            "#,
105            ident = sym $ident,
106        }
107    };
108}
109
110rodata!(sel4_reset_regions_start);
111rodata!(sel4_reset_regions_meta_offset);
112rodata!(sel4_reset_regions_meta_count);
113rodata!(sel4_reset_regions_data_offset);
114rodata!(sel4_reset_regions_data_size);
115
116// // //
117
118pub fn reset() -> ! {
119    unsafe {
120        _reset();
121    }
122    unreachable!()
123}
124
125unsafe extern "C" {
126    fn _reset();
127}
128
129global_asm! {
130    r#"
131        .extern _start
132
133        .global _reset
134
135        .section .text
136
137        _reset:
138    "#,
139    #[cfg(target_arch = "aarch64")]
140    r#"
141            ldr x9, =__sel4_reset__stack_bottom
142            ldr x9, [x9]
143            mov sp, x9
144            bl __sel4_reset__reset_memory
145            b _start
146
147        1:  b 1b
148    "#,
149}