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