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