1use core::sync::atomic::Ordering;
4
5const LOGO: &str = r#"
6 d8888 .d88888b. .d8888b.
7 d88888 d88P" "Y88b d88P Y88b
8 d88P888 888 888 Y88b.
9 d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
10 d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b.
11 d88P 888 888 888 88888888 888 888 "888
12 d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P
13d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P"
14"#;
15
16#[cfg(feature = "paging")]
17fn runtime_page_fault_handler(
18 addr: ax_memory_addr::VirtAddr,
19 flags: ax_hal::trap::PageFaultFlags,
20) -> bool {
21 #[cfg(feature = "stack-guard-page")]
22 if crate::diagnostics::diagnose_current_stack_guard_page_fault(addr) {
23 return false;
24 }
25
26 crate::kernel_mapping::handle_kernel_page_fault(addr, flags)
27}
28
29pub(super) fn initialize_scheduler_before_platform<E>(
36 initialize_scheduler: impl FnOnce() -> Result<(), E>,
37 initialize_platform: impl FnOnce(),
38) -> Result<(), E> {
39 initialize_scheduler()?;
40 initialize_platform();
41 Ok(())
42}
43
44fn initialize_primary_platform(cpu_id: usize, arg: usize) {
45 info!("Initialize platform devices...");
46 ax_hal::init_later(cpu_id, arg);
47 if rdrive::is_initialized() {
48 crate::registers::append_linker_registers();
49 ax_hal::irq::init_boot_irqs(cpu_id)
50 .unwrap_or_else(|error| panic!("failed to initialize boot IRQs: {error:?}"));
51 } else {
52 warn!("rdrive is not initialized; skip pre-kernel driver probe");
53 }
54}
55
56#[cfg_attr(not(test), ax_plat::main)]
67pub fn rust_main(cpu_id: usize, arg: usize) -> ! {
68 ax_hal::percpu::init_primary(cpu_id);
69 crate::guard::assert_boot_preemption_held();
70 ax_alloc::init_percpu_slab(cpu_id);
73 ax_hal::init_early(cpu_id, arg);
74 let log_level = option_env!("AX_LOG").unwrap_or("info");
75
76 ax_println!("{}", LOGO);
77 ax_println!(
78 indoc::indoc! {"
79 arch = {}
80 platform = {}
81 target = {}
82 build_mode = {}
83 log_level = {}
84 backtrace = {}
85 smp = {}
86 "},
87 crate::build_info::ARCH,
88 crate::hal::platform_name(),
89 crate::build_info::TARGET,
90 crate::build_info::MODE,
91 log_level,
92 axbacktrace::is_enabled(),
93 ax_hal::cpu_num()
94 );
95
96 ax_log::init();
97 ax_log::set_max_level(log_level); info!("Logging is enabled.");
99 info!("Primary CPU {cpu_id} started, arg = {arg:#x}.");
100
101 info!("Found physcial memory regions:");
102 for region in ax_hal::mem::memory_regions() {
103 info!(
104 " [{:x?}, {:x?}) {} ({:?})",
105 region.paddr,
106 region.paddr + region.size,
107 region.name,
108 region.flags
109 );
110 }
111
112 crate::boot_memory::init_allocator();
113
114 #[cfg(feature = "std-compat")]
115 crate::panic_output::install_std_hook();
116
117 #[cfg(kernel_tls)]
118 crate::thread::initialize_early_bootstrap_tls()
119 .expect("failed to initialize primary bootstrap TLS");
120
121 let layout = ax_hal::mem::virtual_address_space()
122 .expect("platform virtual-address layout must be supported");
123 let kernel_space_start = layout.kernel().start;
124 let kernel_space_size = layout.kernel().size();
125
126 {
127 use core::ops::Range;
128
129 unsafe extern "C" {
130 safe static _stext: [u8; 0];
131 safe static _etext: [u8; 0];
132 }
133
134 let fp_range_start = kernel_space_start.as_usize();
135 let fp_range_end = fp_range_start.saturating_add(kernel_space_size);
136 axbacktrace::init(
137 Range {
138 start: _stext.as_ptr() as usize,
139 end: _etext.as_ptr() as usize,
140 },
141 Range {
142 start: fp_range_start,
143 end: fp_range_end,
144 },
145 );
146 }
147
148 info!(
149 "kernel aspace: [{:#x?}, {:#x?})",
150 kernel_space_start,
151 kernel_space_start + kernel_space_size,
152 );
153
154 #[cfg(feature = "paging")]
155 {
156 ax_mm::init_memory_management();
157 ax_hal::trap::set_page_fault_handler(runtime_page_fault_handler);
158 }
159 initialize_scheduler_before_platform(
160 || crate::thread::initialize_primary(cpu_id),
161 || initialize_primary_platform(cpu_id, arg),
162 )
163 .expect("failed to initialize primary task scheduler");
164
165 #[cfg(any(feature = "ipi", feature = "wake-ipi"))]
166 {
167 ax_ipi::init();
168 #[cfg(feature = "ipi")]
169 ax_hal::irq::set_run_on_cpu_sync(crate::ipi_delivery::run_on_cpu_sync);
170 }
171 {
172 info!("Initialize interrupt handlers...");
173 crate::interrupt_bootstrap::init_current_cpu();
174 }
175
176 #[cfg(feature = "paging")]
177 let tlb_preparation = ax_hal::cache::prepare_current_cpu_tlb()
178 .expect("primary CPU failed to prepare TLB capability");
179
180 #[cfg(any(feature = "ipi", feature = "wake-ipi"))]
184 ax_ipi::mark_current_cpu_ready();
185 let online_cpu = crate::thread::publish_current_cpu_online()
186 .expect("failed to publish primary scheduler CPU");
187 crate::thread::start_current_ktimer_service().expect("failed to create primary ktimer service");
188 crate::clock_event_runtime::enable_irqs_after_scheduler_online(online_cpu);
189 #[cfg(feature = "paging")]
190 ax_hal::cache::publish_current_cpu_tlb_ready(tlb_preparation)
191 .expect("primary CPU failed to publish TLB readiness");
192 crate::guard::release_bootstrap_preemption();
193 crate::thread::start_deferred_task_work_service()
194 .expect("failed to start deferred scheduler task-work service");
195
196 crate::devices::probe_all_devices();
197 crate::serial::init(cpu_id);
198 match crate::console::activate_before_smp() {
199 crate::console::ConsoleActivation::Active {
200 runtime_index,
201 tty_number,
202 } => info!("runtime console active: serial{runtime_index}, ttyS{tty_number}"),
203 crate::console::ConsoleActivation::RawHal(reason) => {
204 info!("no runtime console selected; keeping the HAL console: {reason:?}")
205 }
206 crate::console::ConsoleActivation::FailedClosed(reason) => {
207 warn!("runtime console unavailable; early console failed closed: {reason:?}")
208 }
209 }
210
211 #[cfg(feature = "rtc")]
212 ax_println!(
213 "Boot at {}\n",
214 chrono::DateTime::from_timestamp_nanos(ax_hal::time::wall_time_nanos() as _),
215 );
216
217 crate::fs::init(ax_hal::boot::bootargs());
218
219 #[cfg(feature = "display")]
220 crate::devices::init_display();
221
222 #[cfg(feature = "input")]
223 crate::devices::init_input();
224
225 #[cfg(feature = "net")]
226 crate::devices::init_net();
227
228 #[cfg(feature = "vsock")]
229 crate::devices::init_vsock();
230
231 #[cfg(feature = "smp")]
232 crate::mp::start_secondary_cpus(cpu_id);
233
234 ax_ctor_bare::call_ctors();
235
236 info!("Primary CPU {cpu_id} init OK.");
237 crate::INITED_CPUS.fetch_add(1, Ordering::Release);
238
239 while !crate::is_init_ok() {
240 core::hint::spin_loop();
241 }
242
243 #[cfg(any(feature = "ipi", feature = "wake-ipi"))]
244 ax_ipi::wait_for_all_cpus_ready();
245
246 #[cfg(all(feature = "smp", feature = "ipi"))]
247 crate::fs::online_smp();
248
249 crate::ax_app_entry();
250 crate::terminate();
251}
252
253#[cfg(test)]
254mod tests {
255 use alloc::vec::Vec;
256 use core::cell::RefCell;
257
258 use super::initialize_scheduler_before_platform;
259
260 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
261 enum BootEvent {
262 SchedulerOwnerPublished,
263 PlatformLateInit,
264 }
265
266 #[test]
267 fn scheduler_owner_is_published_before_platform_late_init() {
268 let events = RefCell::new(Vec::new());
269 initialize_scheduler_before_platform(
270 || {
271 events.borrow_mut().push(BootEvent::SchedulerOwnerPublished);
272 Ok::<(), ()>(())
273 },
274 || events.borrow_mut().push(BootEvent::PlatformLateInit),
275 )
276 .unwrap();
277
278 assert_eq!(
279 events.into_inner(),
280 [
281 BootEvent::SchedulerOwnerPublished,
282 BootEvent::PlatformLateInit,
283 ]
284 );
285 }
286}