1#![no_std]
8#![deny(clippy::undocumented_unsafe_blocks)]
9#![deny(unsafe_op_in_unsafe_fn)]
10
11#[cfg(any(
12 all(feature = "el1", feature = "el2"),
13 all(feature = "el1", feature = "el3"),
14 all(feature = "el2", feature = "el3"),
15))]
16compile_error!("Only one `el` feature may be enabled at once.");
17
18#[cfg(feature = "exceptions")]
19use core::arch::asm;
20use core::arch::global_asm;
21
22global_asm!(include_str!("entry.S"));
23
24#[cfg(not(feature = "initial-pagetable"))]
25global_asm!(include_str!("dummy_enable_mmu.S"),);
26#[cfg(all(feature = "el1", feature = "initial-pagetable"))]
27global_asm!(include_str!("el1_enable_mmu.S"),);
28#[cfg(all(feature = "el2", feature = "initial-pagetable"))]
29global_asm!(include_str!("el2_enable_mmu.S"));
30#[cfg(all(feature = "el3", feature = "initial-pagetable"))]
31global_asm!(include_str!("el3_enable_mmu.S"));
32
33#[cfg(feature = "exceptions")]
34global_asm!(include_str!("exceptions.S"));
35
36unsafe extern "C" {
37 pub unsafe fn secondary_entry(stack_end: *mut u64) -> !;
43}
44
45#[unsafe(no_mangle)]
48extern "C" fn set_exception_vector() {
49 #[cfg(all(feature = "el1", feature = "exceptions"))]
51 unsafe {
52 asm!(
53 "adr x9, vector_table_el1",
54 "msr vbar_el1, x9",
55 options(nomem, nostack),
56 out("x9") _,
57 );
58 }
59 #[cfg(all(feature = "el2", feature = "exceptions"))]
61 unsafe {
62 asm!(
63 "adr x9, vector_table_el2",
64 "msr vbar_el2, x9",
65 options(nomem, nostack),
66 out("x9") _,
67 );
68 }
69 #[cfg(all(feature = "el3", feature = "exceptions"))]
71 unsafe {
72 asm!(
73 "adr x9, vector_table_el3",
74 "msr vbar_el3, x9",
75 options(nomem, nostack),
76 out("x9") _,
77 );
78 }
79}
80
81#[unsafe(no_mangle)]
82extern "C" fn rust_entry(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> ! {
83 set_exception_vector();
84 __main(arg0, arg1, arg2, arg3)
85}
86
87unsafe extern "Rust" {
88 safe fn __main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> !;
90}
91
92#[macro_export]
109macro_rules! entry {
110 ($name:path) => {
111 entry!($name, 40);
112 };
113 ($name:path, $boot_stack_pages:expr) => {
114 #[unsafe(export_name = "boot_stack")]
115 #[unsafe(link_section = ".stack.boot_stack")]
116 static mut __BOOT_STACK: $crate::Stack<$boot_stack_pages> = $crate::Stack::new();
117
118 #[unsafe(export_name = "__main")]
120 fn __main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) -> ! {
121 $name(arg0, arg1, arg2, arg3)
123 }
124 };
125}
126
127#[cfg(feature = "initial-pagetable")]
131#[macro_export]
132macro_rules! initial_pagetable {
133 ($value:expr) => {
134 #[unsafe(export_name = "initial_pagetable")]
135 #[unsafe(link_section = ".rodata.initial_pagetable")]
136 static INITIAL_PAGETABLE: $crate::InitialPagetable = $value;
137 };
138}
139
140#[repr(C, align(4096))]
142pub struct InitialPagetable(pub [usize; 512]);
143
144#[repr(C, align(4096))]
148pub struct Stack<const NUM_PAGES: usize>([StackPage; NUM_PAGES]);
149
150impl<const NUM_PAGES: usize> Stack<NUM_PAGES> {
151 pub const fn new() -> Self {
153 Self([const { StackPage::new() }; NUM_PAGES])
154 }
155}
156
157impl<const NUM_PAGES: usize> Default for Stack<NUM_PAGES> {
158 fn default() -> Self {
159 Self::new()
160 }
161}
162
163#[repr(C, align(4096))]
164struct StackPage([u8; 4096]);
165
166impl StackPage {
167 const fn new() -> Self {
168 Self([0; 4096])
169 }
170}
171
172#[cfg(feature = "psci")]
173pub unsafe fn start_core<C: smccc::Call, const N: usize>(
187 mpidr: u64,
188 stack: *mut Stack<N>,
189 rust_entry: extern "C" fn(arg: u64) -> !,
190 arg: u64,
191) -> Result<(), smccc::psci::Error> {
192 assert!(stack.is_aligned());
193 let stack_end = stack.wrapping_add(1);
195
196 let params = stack_end as *mut u64;
198 unsafe {
200 *params.wrapping_sub(1) = rust_entry as _;
201 *params.wrapping_sub(2) = arg;
202 }
203 dsb_st();
205
206 smccc::psci::cpu_on::<C>(mpidr, secondary_entry as _, stack_end as _)
207}
208
209#[cfg(feature = "psci")]
211fn dsb_st() {
212 unsafe {
214 asm!("dsb st", options(nostack));
215 }
216}