hermit/arch/x86_64/kernel/
mod.rs1#[cfg(feature = "common-os")]
2use core::arch::asm;
3use core::ptr;
4#[cfg(feature = "common-os")]
5use core::slice;
6use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
7
8use x86_64::registers::control::{Cr0, Cr4};
9
10pub(crate) use self::apic::{set_oneshot_timer, wakeup_core};
11use crate::arch::kernel::core_local::*;
12#[cfg(any(target_os = "none", feature = "uhyve"))]
13use crate::env;
14#[cfg(feature = "uhyve")]
15use crate::env::UhyveStartInfo;
16
17#[cfg(feature = "acpi")]
18mod acpi;
19pub mod apic;
20#[cfg(all(target_arch = "x86_64", feature = "bga"))]
21pub mod bga;
22pub mod core_local;
23pub mod gdt;
24pub mod interrupts;
25#[cfg(feature = "kernel-stack")]
26pub mod kernel_stack;
27#[cfg(all(not(feature = "pci"), feature = "virtio"))]
28pub mod mmio;
29#[cfg(feature = "pc-keyboard")]
30pub mod pc_keyboard;
31#[cfg(feature = "pci")]
32pub mod pci;
33pub mod pic;
34pub mod pit;
35pub mod processor;
36pub mod scheduler;
37pub mod serial;
38pub mod switch;
39#[cfg(feature = "common-os")]
40mod syscall;
41pub(crate) mod systemtime;
42#[cfg(feature = "vga")]
43pub mod vga;
44
45#[cfg(feature = "smp")]
46pub fn get_possible_cpus() -> u32 {
47 #[cfg(feature = "uhyve")]
48 if let Some(num_cpus) = env::start_info().uhyve_num_cpus() {
49 return num_cpus.get().try_into().unwrap();
50 }
51
52 apic::local_apic_id_count()
53}
54
55#[cfg(feature = "smp")]
56pub fn get_processor_count() -> u32 {
57 CPU_ONLINE.load(Ordering::Acquire)
58}
59
60#[cfg(not(feature = "smp"))]
61pub fn get_processor_count() -> u32 {
62 1
63}
64
65#[cfg(target_os = "none")]
67pub fn boot_processor_init() {
68 processor::detect_features();
69 processor::configure();
70
71 #[cfg(feature = "vga")]
72 vga::init();
73
74 crate::mm::init();
75 crate::mm::print_information();
76 CoreLocal::get().add_irq_counter();
77 env::init();
78 gdt::add_current_core();
79 interrupts::load_idt();
80 pic::init();
81
82 processor::detect_frequency();
83 crate::logging::KERNEL_LOGGER.set_time(true);
84 processor::print_information();
85 debug!("Cr0 = {:?}", Cr0::read());
86 debug!("Cr4 = {:?}", Cr4::read());
87 interrupts::install();
88 systemtime::init();
89
90 #[cfg(feature = "acpi")]
91 acpi::init();
92
93 #[cfg(feature = "pci")]
94 pci::init();
95
96 apic::init();
97 scheduler::install_timer_handler();
98 finish_processor_init();
99}
100
101#[cfg(all(target_os = "none", feature = "smp"))]
103pub fn application_processor_init() {
104 CoreLocal::install();
105 processor::configure();
106 gdt::add_current_core();
107 interrupts::load_idt();
108 if processor::supports_x2apic() {
109 apic::init_x2apic();
110 }
111 apic::init_local_apic();
112 debug!("Cr0 = {:?}", Cr0::read());
113 debug!("Cr4 = {:?}", Cr4::read());
114 finish_processor_init();
115}
116
117fn finish_processor_init() {
118 #[cfg(feature = "uhyve")]
119 if env::start_info().is_uhyve() {
120 apic::add_local_apic_id(core_id() as u8);
125
126 #[cfg(feature = "smp")]
129 apic::init_next_processor_variables();
130 }
131}
132
133pub fn boot_next_processor() {
134 let cpu_online = CPU_ONLINE.fetch_add(1, Ordering::Release);
137
138 #[cfg(feature = "uhyve")]
139 if env::start_info().is_uhyve() {
140 return;
141 }
142
143 if cpu_online == 0 {
144 #[cfg(all(target_os = "none", feature = "smp"))]
145 apic::boot_application_processors();
146 }
147
148 if !cfg!(feature = "smp") {
149 apic::print_information();
150 }
151}
152
153pub fn print_statistics() {
154 interrupts::print_statistics();
155}
156
157pub static CPU_ONLINE: AtomicU32 = AtomicU32::new(0);
161
162pub static CURRENT_STACK_ADDRESS: AtomicPtr<u8> = AtomicPtr::new(ptr::null_mut());
163
164#[cfg(feature = "common-os")]
165const LOADER_START: usize = 0x0100_0000_0000;
166#[cfg(feature = "common-os")]
167const LOADER_STACK_SIZE: usize = 0x8000;
168
169#[cfg(feature = "common-os")]
170pub fn load_application<F, T>(code_size: u64, tls_size: u64, func: F) -> T
171where
172 F: FnOnce(&'static mut [u8], Option<&'static mut [u8]>) -> T,
173{
174 use align_address::Align;
175 use free_list::PageLayout;
176 use memory_addresses::{PhysAddr, VirtAddr};
177 use x86_64::structures::paging::{PageSize, Size4KiB as BasePageSize};
178
179 use crate::arch::mm::paging::{self, PageTableEntryFlags, PageTableEntryFlagsExt};
180 use crate::mm::{FrameAlloc, PageRangeAllocator};
181
182 let code_size = (code_size as usize + LOADER_STACK_SIZE).align_up(BasePageSize::SIZE as usize);
183 let layout = PageLayout::from_size_align(code_size, BasePageSize::SIZE as usize).unwrap();
184 let frame_range = FrameAlloc::allocate(layout).unwrap();
185 let physaddr = PhysAddr::from(frame_range.start());
186
187 let mut flags = PageTableEntryFlags::empty();
188 flags.normal().writable().user().execute_enable();
189 paging::map::<BasePageSize>(
190 VirtAddr::from(LOADER_START),
191 physaddr,
192 code_size / BasePageSize::SIZE as usize,
193 flags,
194 );
195
196 let loader_start_ptr = ptr::with_exposed_provenance_mut(LOADER_START);
197 let code_slice = unsafe { slice::from_raw_parts_mut(loader_start_ptr, code_size) };
198
199 if tls_size > 0 {
200 let tcb_size = size_of::<*mut ()>();
205 let tls_offset = tls_size as usize;
206
207 let tls_memsz = (tls_offset + tcb_size).align_up(BasePageSize::SIZE as usize);
208 let layout = PageLayout::from_size(tls_memsz).unwrap();
209 let frame_range = FrameAlloc::allocate(layout).unwrap();
210 let physaddr = PhysAddr::from(frame_range.start());
211
212 let mut flags = PageTableEntryFlags::empty();
213 flags.normal().writable().user().execute_disable();
214 let tls_virt = VirtAddr::from(LOADER_START + code_size + BasePageSize::SIZE as usize);
215 paging::map::<BasePageSize>(
216 tls_virt,
217 physaddr,
218 tls_memsz / BasePageSize::SIZE as usize,
219 flags,
220 );
221 let block =
222 unsafe { slice::from_raw_parts_mut(tls_virt.as_mut_ptr(), tls_offset + tcb_size) };
223 for elem in block.iter_mut() {
224 *elem = 0;
225 }
226
227 let thread_ptr = block[tls_offset..].as_mut_ptr().cast::<()>();
229 unsafe {
230 thread_ptr.cast::<*mut ()>().write(thread_ptr);
231 }
232 processor::writefs(thread_ptr.expose_provenance());
233
234 func(code_slice, Some(block))
235 } else {
236 func(code_slice, None)
237 }
238}
239
240#[cfg(feature = "common-os")]
241pub unsafe fn jump_to_user_land(entry_point: usize, code_size: usize, arg: &[&str]) -> ! {
242 use alloc::ffi::CString;
243
244 use align_address::Align;
245 use x86_64::structures::paging::{PageSize, Size4KiB as BasePageSize};
246
247 use crate::arch::kernel::scheduler::TaskStacks;
248
249 info!("Create new file descriptor table");
250 core_scheduler().recreate_objmap().unwrap();
251
252 let entry_point: usize = LOADER_START | entry_point;
253 let stack_pointer: usize = LOADER_START
254 + (code_size + LOADER_STACK_SIZE).align_up(BasePageSize::SIZE.try_into().unwrap())
255 - 8;
256
257 let stack_pointer = stack_pointer - 128 - arg.len() * size_of::<*mut u8>();
258 let stack_ptr = ptr::with_exposed_provenance_mut::<*mut u8>(stack_pointer);
259 let argv = unsafe { slice::from_raw_parts_mut(stack_ptr, arg.len()) };
260 let len = arg.iter().fold(0, |acc, x| acc + x.len() + 1);
261 let stack_pointer = (stack_pointer - len).align_down(16) - size_of::<usize>();
263
264 let mut pos: usize = 0;
265 for (i, s) in arg.iter().enumerate() {
266 let s = CString::new(*s).unwrap();
267 let bytes = s.as_bytes_with_nul();
268 argv[i] = ptr::with_exposed_provenance_mut::<u8>(stack_pointer + pos);
269 pos += bytes.len();
270
271 unsafe {
272 argv[i].copy_from_nonoverlapping(bytes.as_ptr(), bytes.len());
273 }
274 }
275
276 debug!("Jump to user space at 0x{entry_point:x}, stack pointer 0x{stack_pointer:x}");
277
278 unsafe {
279 asm!(
280 "and rsp, {0}",
281 "swapgs",
282 "push {1}",
283 "push {2}",
284 "push {3}",
285 "push {4}",
286 "push {5}",
287 "mov rdi, {6}",
288 "mov rsi, {7}",
289 "iretq",
290 const u64::MAX - (TaskStacks::MARKER_SIZE as u64 - 1),
291 const 0x23usize,
292 in(reg) stack_pointer,
293 const 0x1202u64,
294 const 0x2busize,
295 in(reg) entry_point,
296 in(reg) argv.len(),
297 in(reg) argv.as_ptr(),
298 options(nostack, noreturn)
299 );
300 }
301}