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 cfg_if::cfg_if;
14
15use sel4_stack::{Stack, StackBottom};
16
17// // //
18
19#[repr(C)]
20#[derive(Debug)]
21struct RegionMeta {
22    vaddr: usize,
23    offset: usize,
24    filesz: usize,
25    memsz: usize,
26}
27
28struct Regions<'a> {
29    meta: &'a [RegionMeta],
30    data: &'a [u8],
31}
32
33impl Regions<'_> {
34    unsafe fn reset_memory(&self) {
35        for meta in self.meta {
36            let dst = unsafe { slice::from_raw_parts_mut(meta.vaddr as *mut _, meta.memsz) };
37            let (dst_data, dst_zero) = dst.split_at_mut(meta.filesz);
38            let src_data = &self.data[meta.offset..][..meta.filesz];
39            dst_data.copy_from_slice(src_data);
40            ptr::write_bytes(dst_zero.as_mut_ptr(), 0, dst_zero.len());
41        }
42    }
43}
44
45// // //
46
47const STACK_SIZE: usize = 4096;
48
49#[link_section = ".persistent"]
50static STACK: Stack<STACK_SIZE> = Stack::new();
51
52#[no_mangle]
53static __sel4_reset__stack_bottom: StackBottom = STACK.bottom();
54
55// // //
56
57#[no_mangle]
58unsafe extern "C" fn __sel4_reset__reset_memory() {
59    unsafe {
60        get_regions().reset_memory();
61    }
62}
63
64unsafe fn get_regions() -> Regions<'static> {
65    Regions {
66        meta: slice::from_raw_parts(
67            (sel4_reset_regions_start + sel4_reset_regions_meta_offset) as *const _,
68            sel4_reset_regions_meta_count,
69        ),
70        data: slice::from_raw_parts(
71            (sel4_reset_regions_start + sel4_reset_regions_data_offset) as *const _,
72            sel4_reset_regions_data_size,
73        ),
74    }
75}
76
77// HACK to force variables into .rodata without causing .rodata to end up in a PF_W segment
78macro_rules! rodata {
79    ($ident:ident) => {
80        extern "C" {
81            static $ident: usize;
82        }
83        global_asm! {
84            ".section .rodata",
85            concat!(".global ", stringify!($ident)),
86            concat!(stringify!($ident), ": ", asm_word_size!(), " 0"),
87            concat!(".size ", stringify!($ident), ", .-", stringify!($ident)),
88        }
89    };
90}
91
92cfg_if! {
93    if #[cfg(target_pointer_width = "64")] {
94        macro_rules! asm_word_size {
95            () => {
96                ".quad"
97            }
98        }
99    } else if #[cfg(target_pointer_width = "32")] {
100        macro_rules! asm_word_size {
101            () => {
102                ".word"
103            }
104        }
105    } else {
106        compile_error!("unsupported configuration");
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
125extern "C" {
126    fn _reset();
127}
128
129macro_rules! common_asm_prefix {
130    () => {
131        r#"
132            .extern _start
133
134            .global _reset
135
136            .section .text
137
138            _reset:
139        "#
140    };
141}
142
143cfg_if::cfg_if! {
144    if #[cfg(target_arch = "aarch64")] {
145        global_asm! {
146            common_asm_prefix!(),
147            r#"
148                    ldr x9, =__sel4_reset__stack_bottom
149                    ldr x9, [x9]
150                    mov sp, x9
151                    bl __sel4_reset__reset_memory
152                    b _start
153        
154                1:  b 1b
155            "#
156        }
157    } else {
158        compile_error!("unsupported architecture");
159    }
160}