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            unsafe {
41                ptr::write_bytes(dst_zero.as_mut_ptr(), 0, dst_zero.len());
42            }
43        }
44    }
45}
46
47// // //
48
49const STACK_SIZE: usize = 4096;
50
51#[unsafe(link_section = ".persistent")]
52static STACK: Stack<STACK_SIZE> = Stack::new();
53
54#[unsafe(no_mangle)]
55static __sel4_reset__stack_bottom: StackBottom = STACK.bottom();
56
57// // //
58
59#[unsafe(no_mangle)]
60unsafe extern "C" fn __sel4_reset__reset_memory() {
61    unsafe {
62        get_regions().reset_memory();
63    }
64}
65
66unsafe fn get_regions() -> Regions<'static> {
67    unsafe {
68        Regions {
69            meta: slice::from_raw_parts(
70                (sel4_reset_regions_start + sel4_reset_regions_meta_offset) as *const _,
71                sel4_reset_regions_meta_count,
72            ),
73            data: slice::from_raw_parts(
74                (sel4_reset_regions_start + sel4_reset_regions_data_offset) as *const _,
75                sel4_reset_regions_data_size,
76            ),
77        }
78    }
79}
80
81// HACK to force variables into .rodata without causing .rodata to end up in a PF_W segment
82macro_rules! rodata {
83    ($ident:ident) => {
84        unsafe extern "C" {
85            static $ident: usize;
86        }
87        global_asm! {
88            ".section .rodata",
89            concat!(".global ", stringify!($ident)),
90            concat!(stringify!($ident), ": ", asm_word_size!(), " 0"),
91            concat!(".size ", stringify!($ident), ", .-", stringify!($ident)),
92        }
93    };
94}
95
96cfg_if! {
97    if #[cfg(target_pointer_width = "64")] {
98        macro_rules! asm_word_size {
99            () => {
100                ".quad"
101            }
102        }
103    } else if #[cfg(target_pointer_width = "32")] {
104        macro_rules! asm_word_size {
105            () => {
106                ".word"
107            }
108        }
109    } else {
110        compile_error!("unsupported configuration");
111    }
112}
113
114rodata!(sel4_reset_regions_start);
115rodata!(sel4_reset_regions_meta_offset);
116rodata!(sel4_reset_regions_meta_count);
117rodata!(sel4_reset_regions_data_offset);
118rodata!(sel4_reset_regions_data_size);
119
120// // //
121
122pub fn reset() -> ! {
123    unsafe {
124        _reset();
125    }
126    unreachable!()
127}
128
129unsafe extern "C" {
130    fn _reset();
131}
132
133macro_rules! common_asm_prefix {
134    () => {
135        r#"
136            .extern _start
137
138            .global _reset
139
140            .section .text
141
142            _reset:
143        "#
144    };
145}
146
147cfg_if::cfg_if! {
148    if #[cfg(target_arch = "aarch64")] {
149        global_asm! {
150            common_asm_prefix!(),
151            r#"
152                    ldr x9, =__sel4_reset__stack_bottom
153                    ldr x9, [x9]
154                    mov sp, x9
155                    bl __sel4_reset__reset_memory
156                    b _start
157        
158                1:  b 1b
159            "#
160        }
161    } else {
162        compile_error!("unsupported architecture");
163    }
164}