1#![cfg_attr(not(test), no_std)]
20#![feature(doc_auto_cfg)]
21
22#[macro_use]
23extern crate axlog;
24
25#[cfg(all(target_os = "none", not(test)))]
26mod lang_items;
27
28#[cfg(feature = "smp")]
29mod mp;
30
31#[cfg(feature = "smp")]
32pub use self::mp::rust_main_secondary;
33
34const LOGO: &str = r#"
35 d8888 .d88888b. .d8888b.
36 d88888 d88P" "Y88b d88P Y88b
37 d88P888 888 888 Y88b.
38 d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
39 d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b.
40 d88P 888 888 888 88888888 888 888 "888
41 d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P
42d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P"
43"#;
44
45unsafe extern "C" {
46 fn main();
47}
48
49struct LogIfImpl;
50
51#[crate_interface::impl_interface]
52impl axlog::LogIf for LogIfImpl {
53 fn console_write_str(s: &str) {
54 axhal::console::write_bytes(s.as_bytes());
55 }
56
57 fn current_time() -> core::time::Duration {
58 axhal::time::monotonic_time()
59 }
60
61 fn current_cpu_id() -> Option<usize> {
62 #[cfg(feature = "smp")]
63 if is_init_ok() {
64 Some(axhal::cpu::this_cpu_id())
65 } else {
66 None
67 }
68 #[cfg(not(feature = "smp"))]
69 Some(0)
70 }
71
72 fn current_task_id() -> Option<u64> {
73 if is_init_ok() {
74 #[cfg(feature = "multitask")]
75 {
76 axtask::current_may_uninit().map(|curr| curr.id().as_u64())
77 }
78 #[cfg(not(feature = "multitask"))]
79 None
80 } else {
81 None
82 }
83 }
84}
85
86use core::sync::atomic::{AtomicUsize, Ordering};
87
88static INITED_CPUS: AtomicUsize = AtomicUsize::new(0);
89
90fn is_init_ok() -> bool {
91 INITED_CPUS.load(Ordering::Acquire) == axconfig::SMP
92}
93
94#[cfg_attr(not(test), unsafe(no_mangle))]
104pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! {
105 ax_println!("{}", LOGO);
106 ax_println!(
107 "\
108 arch = {}\n\
109 platform = {}\n\
110 target = {}\n\
111 build_mode = {}\n\
112 log_level = {}\n\
113 smp = {}\n\
114 ",
115 axconfig::ARCH,
116 axconfig::PLATFORM,
117 option_env!("AX_TARGET").unwrap_or(""),
118 option_env!("AX_MODE").unwrap_or(""),
119 option_env!("AX_LOG").unwrap_or(""),
120 axconfig::SMP,
121 );
122 #[cfg(feature = "rtc")]
123 ax_println!(
124 "Boot at {}\n",
125 chrono::DateTime::from_timestamp_nanos(axhal::time::wall_time_nanos() as _),
126 );
127
128 axlog::init();
129 axlog::set_max_level(option_env!("AX_LOG").unwrap_or("")); info!("Logging is enabled.");
131 info!("Primary CPU {} started, dtb = {:#x}.", cpu_id, dtb);
132
133 info!("Found physcial memory regions:");
134 for r in axhal::mem::memory_regions() {
135 info!(
136 " [{:x?}, {:x?}) {} ({:?})",
137 r.paddr,
138 r.paddr + r.size,
139 r.name,
140 r.flags
141 );
142 }
143
144 #[cfg(feature = "alloc")]
145 init_allocator();
146
147 #[cfg(feature = "paging")]
148 axmm::init_memory_management();
149
150 info!("Initialize platform devices...");
151 axhal::platform_init();
152
153 #[cfg(feature = "multitask")]
154 axtask::init_scheduler();
155
156 #[cfg(any(feature = "fs", feature = "net", feature = "display"))]
157 {
158 #[allow(unused_variables)]
159 let all_devices = axdriver::init_drivers();
160
161 #[cfg(feature = "fs")]
162 axfs::init_filesystems(all_devices.block);
163
164 #[cfg(feature = "net")]
165 axnet::init_network(all_devices.net);
166
167 #[cfg(feature = "display")]
168 axdisplay::init_display(all_devices.display);
169 }
170
171 #[cfg(feature = "smp")]
172 self::mp::start_secondary_cpus(cpu_id);
173
174 #[cfg(feature = "irq")]
175 {
176 info!("Initialize interrupt handlers...");
177 init_interrupt();
178 }
179
180 #[cfg(all(feature = "tls", not(feature = "multitask")))]
181 {
182 info!("Initialize thread local storage...");
183 init_tls();
184 }
185
186 ctor_bare::call_ctors();
187
188 info!("Primary CPU {} init OK.", cpu_id);
189 INITED_CPUS.fetch_add(1, Ordering::Relaxed);
190
191 while !is_init_ok() {
192 core::hint::spin_loop();
193 }
194
195 unsafe { main() };
196
197 #[cfg(feature = "multitask")]
198 axtask::exit(0);
199 #[cfg(not(feature = "multitask"))]
200 {
201 debug!("main task exited: exit_code={}", 0);
202 axhal::misc::terminate();
203 }
204}
205
206#[cfg(feature = "alloc")]
207fn init_allocator() {
208 use axhal::mem::{MemRegionFlags, memory_regions, phys_to_virt};
209
210 info!("Initialize global memory allocator...");
211 info!(" use {} allocator.", axalloc::global_allocator().name());
212
213 let mut max_region_size = 0;
214 let mut max_region_paddr = 0.into();
215 for r in memory_regions() {
216 if r.flags.contains(MemRegionFlags::FREE) && r.size > max_region_size {
217 max_region_size = r.size;
218 max_region_paddr = r.paddr;
219 }
220 }
221 for r in memory_regions() {
222 if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr {
223 axalloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size);
224 break;
225 }
226 }
227 for r in memory_regions() {
228 if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr {
229 axalloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size)
230 .expect("add heap memory region failed");
231 }
232 }
233}
234
235#[cfg(feature = "irq")]
236fn init_interrupt() {
237 use axhal::time::TIMER_IRQ_NUM;
238
239 const PERIODIC_INTERVAL_NANOS: u64 =
241 axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64;
242
243 #[percpu::def_percpu]
244 static NEXT_DEADLINE: u64 = 0;
245
246 fn update_timer() {
247 let now_ns = axhal::time::monotonic_time_nanos();
248 let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() };
250 if now_ns >= deadline {
251 deadline = now_ns + PERIODIC_INTERVAL_NANOS;
252 }
253 unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) };
254 axhal::time::set_oneshot_timer(deadline);
255 }
256
257 axhal::irq::register_handler(TIMER_IRQ_NUM, || {
258 update_timer();
259 #[cfg(feature = "multitask")]
260 axtask::on_timer_tick();
261 });
262
263 axhal::arch::enable_irqs();
265}
266
267#[cfg(all(feature = "tls", not(feature = "multitask")))]
268fn init_tls() {
269 let main_tls = axhal::tls::TlsArea::alloc();
270 unsafe { axhal::arch::write_thread_pointer(main_tls.tls_ptr() as usize) };
271 core::mem::forget(main_tls);
272}