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