Nothing to see here, move along
at main 491 lines 16 kB view raw
1#![no_std] 2#![no_main] 3#![feature(abi_x86_interrupt)] 4#![allow(clippy::single_match)] 5 6mod acpi; 7mod arch; 8mod cap; 9mod console; 10mod dashboard; 11mod error; 12mod flight; 13mod iommu; 14mod ipc; 15mod irq; 16mod log; 17mod mem; 18mod panic; 19mod pci; 20mod proc; 21#[cfg(lancer_test)] 22mod qemu; 23mod ring; 24mod sched; 25mod static_vec; 26mod sync; 27mod syscall; 28#[cfg(lancer_test)] 29mod test_harness; 30#[cfg(lancer_test)] 31mod tests; 32mod types; 33mod wcet; 34 35use wcet::region::{WcetGuard, WcetTracker}; 36#[cfg(not(lancer_test))] 37use wcet::tsc; 38 39#[unsafe(no_mangle)] 40#[unsafe(naked)] 41extern "C" fn kmain() -> ! { 42 core::arch::naked_asm!( 43 "mov rax, cr0", 44 "and ax, 0xFFFB", 45 "or ax, 0x0002", 46 "mov cr0, rax", 47 "mov rax, cr4", 48 "or ax, 0x0600", 49 "mov cr4, rax", 50 "jmp {entry}", 51 entry = sym kmain_inner, 52 ) 53} 54 55extern "C" fn kmain_inner() -> ! { 56 arch::serial::init(); 57 arch::syscall::init_bsp_percpu(); 58 59 dashboard::dash().add_section("kern", 3); 60 dashboard::dash().add_section("mem", 3); 61 dashboard::dash().add_section("gdt", 1); 62 dashboard::dash().add_section("idt", 1); 63 dashboard::dash().add_section("phys", 2); 64 dashboard::dash().add_section("virt", 1); 65 dashboard::dash().add_section("apic", 2); 66 dashboard::dash().add_section("acpi", 1); 67 dashboard::dash().add_section("ioapic", 2); 68 dashboard::dash().add_section("pci", 1); 69 dashboard::dash().add_section("iommu", 1); 70 dashboard::dash().add_section("cpu", 4); 71 dashboard::dash().add_section("sys", 1); 72 dashboard::dash().add_section("cap", 1); 73 dashboard::dash().add_section("sched", 1); 74 #[cfg(not(lancer_test))] 75 dashboard::dash().add_section("proc", 2); 76 #[cfg(not(lancer_test))] 77 dashboard::dash().add_section("fb", 1); 78 #[cfg(not(lancer_test))] 79 dashboard::dash().add_section("boot", 6); 80 81 #[cfg(not(lancer_test))] 82 let boot_start = tsc::read_tsc(); 83 let mut serial_wcet: WcetTracker<16> = WcetTracker::new("serial_init"); 84 let mut memmap_wcet: WcetTracker<16> = WcetTracker::new("memmap_parse"); 85 let mut gdt_wcet: WcetTracker<16> = WcetTracker::new("gdt_init"); 86 let mut idt_wcet: WcetTracker<16> = WcetTracker::new("idt_init"); 87 let mut phys_wcet: WcetTracker<16> = WcetTracker::new("phys_alloc_init"); 88 let mut virt_wcet: WcetTracker<16> = WcetTracker::new("virt_mem_init"); 89 let mut apic_wcet: WcetTracker<16> = WcetTracker::new("apic_init"); 90 91 serial_wcet.record(0); 92 93 phase_begin!(kern); 94 arch::boot::validate_base_revision(); 95 show!(kern, "limine base revision validated"); 96 97 let hhdm_offset = arch::boot::hhdm_offset(); 98 show!(kern, "hhdm offset {:#x}", hhdm_offset); 99 100 let (phys_base, virt_base) = arch::boot::executable_address(); 101 show!(kern, "kernel phys {:#x} virt {:#x}", phys_base, virt_base); 102 phase_end!(kern); 103 104 phase_begin!(mem); 105 { 106 let _guard = WcetGuard::new(&mut memmap_wcet); 107 let memory_map = arch::boot::memory_map(); 108 show!(mem, "memory map {} entries", memory_map.len()); 109 mem::init(memory_map, hhdm_offset); 110 } 111 proc::address_space::capture_boot_pml4(); 112 console::init(16); 113 { 114 let stats = mem::phys::frame_stats(); 115 show!(mem, "{} total, {} free", stats.0, stats.1); 116 } 117 phase_end!(mem); 118 119 phase_begin!(gdt); 120 { 121 let _guard = WcetGuard::new(&mut gdt_wcet); 122 arch::gdt::init(); 123 } 124 show!(gdt, "loaded"); 125 phase_end!(gdt); 126 127 phase_begin!(idt); 128 { 129 let _guard = WcetGuard::new(&mut idt_wcet); 130 arch::idt::init(); 131 } 132 show!(idt, "32 exception handlers + apic vectors"); 133 phase_end!(idt); 134 135 phase_begin!(phys); 136 { 137 let _guard = WcetGuard::new(&mut phys_wcet); 138 } 139 { 140 let stats = mem::phys::frame_stats(); 141 show!(phys, "{} frames available", stats.1); 142 } 143 phase_end!(phys); 144 145 phase_begin!(virt); 146 let mut mapper = unsafe { arch::paging::init(hhdm_offset) }; 147 let mut allocator = mem::phys::BitmapFrameAllocator; 148 { 149 let _guard = WcetGuard::new(&mut virt_wcet); 150 mem::virt::test_mapping(&mut mapper, &mut allocator); 151 } 152 show!(virt, "page tables initialized"); 153 phase_end!(virt); 154 155 { 156 let mut ptable = proc::PROCESSES.lock(); 157 ptable.init(&mut allocator); 158 } 159 160 phase_begin!(apic); 161 { 162 let _guard = WcetGuard::new(&mut apic_wcet); 163 let apic_base = unsafe { x2apic::lapic::xapic_base() }; 164 mem::virt::map_mmio(&mut mapper, &mut allocator, apic_base, hhdm_offset).expect("map_mmio"); 165 arch::apic::init(hhdm_offset); 166 } 167 show!(apic, "lapic enabled, timer configured"); 168 phase_end!(apic); 169 170 phase_begin!(acpi); 171 let acpi_info = match arch::boot::rsdp_address() { 172 Some(rsdp) => { 173 show!(acpi, "rsdp at {:#x}", rsdp); 174 acpi::parse(rsdp, &mut mapper, &mut allocator, hhdm_offset) 175 } 176 None => { 177 show!(acpi, "no rsdp from bootloader"); 178 None 179 } 180 }; 181 phase_end!(acpi); 182 183 phase_begin!(ioapic); 184 let (com1_gsi, kbd_gsi) = match &acpi_info { 185 Some(info) => { 186 mem::virt::map_mmio(&mut mapper, &mut allocator, info.ioapic_addr, hhdm_offset) 187 .expect("map_mmio"); 188 arch::ioapic::init(info.ioapic_addr); 189 let com1 = info.gsi_for_irq(4); 190 arch::ioapic::route_irq(com1, arch::idt::COM1_VECTOR, 0); 191 let kbd = info.gsi_for_irq(1); 192 arch::ioapic::route_irq(kbd, arch::idt::KBD_VECTOR, 0); 193 show!( 194 ioapic, 195 "com1 gsi {} -> vec {}", 196 com1, 197 arch::idt::COM1_VECTOR 198 ); 199 show!(ioapic, "kbd gsi {} -> vec {}", kbd, arch::idt::KBD_VECTOR); 200 (Some(com1), Some(kbd)) 201 } 202 None => { 203 show!(ioapic, "skipped, no acpi"); 204 (None, None) 205 } 206 }; 207 phase_end!(ioapic); 208 209 phase_begin!(pci); 210 match &acpi_info { 211 Some(info) if !info.mcfg_entries.is_empty() => { 212 acpi::mcfg::cache_mcfg_entries(&info.mcfg_entries); 213 pci::enumerate(&info.mcfg_entries, &mut mapper, &mut allocator, hhdm_offset); 214 let count = pci::DEVICE_TABLE.lock().len(); 215 show!(pci, "{} devices enumerated", count); 216 } 217 _ => { 218 show!(pci, "skipped, no mcfg"); 219 } 220 } 221 phase_end!(pci); 222 223 phase_begin!(iommu); 224 match &acpi_info { 225 Some(info) if info.dmar_info.is_some() => { 226 let dmar = info.dmar_info.as_ref().unwrap(); 227 match iommu::init(dmar, &mut mapper, &mut allocator, hhdm_offset) { 228 Ok(()) => match iommu::enable(&mut allocator, hhdm_offset) { 229 Ok(()) => show!(iommu, "enabled"), 230 Err(e) => { 231 show!(iommu, error, "enable failed {:?}", e); 232 phase_fail!(iommu); 233 } 234 }, 235 Err(e) => { 236 show!(iommu, error, "init failed {:?}", e); 237 phase_fail!(iommu); 238 } 239 } 240 } 241 _ => { 242 show!(iommu, "no dmar table"); 243 } 244 } 245 match dashboard::domain_to_section("iommu") { 246 Some(idx) 247 if !matches!( 248 dashboard::dash().section_status(idx), 249 lancer_log::phase::PhaseStatus::Failed 250 ) => 251 { 252 phase_end!(iommu) 253 } 254 _ => {} 255 } 256 257 let virtio_net_gsi = match &acpi_info { 258 Some(info) => { 259 let dev_table = pci::DEVICE_TABLE.lock(); 260 dev_table 261 .iter() 262 .find(|d| d.vendor_id == 0x1AF4 && d.class_code == 0x02 && d.subclass == 0x00) 263 .map(|d| { 264 let irq = d.interrupt_line; 265 let gsi = info.gsi_for_irq(irq); 266 match d.msix_cap.is_some() { 267 true => {} 268 false => { 269 arch::ioapic::route_irq(gsi, arch::idt::VIRTIO_NET_VECTOR, 0); 270 } 271 } 272 gsi 273 }) 274 } 275 None => None, 276 }; 277 278 syscall::platform::store_platform_info(com1_gsi, kbd_gsi, virtio_net_gsi); 279 280 phase_begin!(cpu); 281 { 282 use x86_64::registers::control::{Cr0, Cr0Flags, Cr4, Cr4Flags}; 283 use x86_64::registers::model_specific::{Efer, EferFlags}; 284 285 unsafe { 286 Efer::update(|flags| *flags |= EferFlags::NO_EXECUTE_ENABLE); 287 } 288 show!(cpu, "nxe enabled"); 289 290 unsafe { 291 Cr0::update(|f| { 292 f.remove(Cr0Flags::EMULATE_COPROCESSOR); 293 f.remove(Cr0Flags::TASK_SWITCHED); 294 f.insert(Cr0Flags::MONITOR_COPROCESSOR); 295 f.insert(Cr0Flags::NUMERIC_ERROR); 296 }); 297 Cr4::update(|f| { 298 f.insert(Cr4Flags::OSFXSR); 299 f.insert(Cr4Flags::OSXMMEXCPT_ENABLE); 300 }); 301 } 302 show!(cpu, "fpu/sse enabled"); 303 304 arch::xsave::init(); 305 arch::xsave::propagate_to_percpu(); 306 307 let leaf7 = core::arch::x86_64::__cpuid_count(7, 0); 308 let has_smep = leaf7.ebx & (1 << 7) != 0; 309 let has_smap = leaf7.ebx & (1 << 20) != 0; 310 311 if has_smep { 312 unsafe { Cr4::update(|f| *f |= Cr4Flags::SUPERVISOR_MODE_EXECUTION_PROTECTION) }; 313 show!(cpu, "smep enabled"); 314 } 315 316 if has_smap { 317 unsafe { Cr4::update(|f| *f |= Cr4Flags::SUPERVISOR_MODE_ACCESS_PREVENTION) }; 318 arch::syscall::set_smap_active(true); 319 show!(cpu, "smap enabled"); 320 } 321 } 322 phase_end!(cpu); 323 324 phase_begin!(sys); 325 arch::syscall::init(); 326 show!(sys, "syscall/sysret configured"); 327 phase_end!(sys); 328 329 phase_begin!(cap); 330 cap::init(&mut allocator); 331 show!(cap, "initialized"); 332 phase_end!(cap); 333 334 phase_begin!(sched); 335 sched::init(); 336 wcet::init(); 337 sched::seed_timer_wheel(); 338 x86_64::instructions::interrupts::enable(); 339 show!(sched, "scheduler + interrupts enabled"); 340 phase_end!(sched); 341 342 #[cfg(lancer_test)] 343 { 344 dashboard::dash().transition_to_streaming(); 345 let _ = (com1_gsi, kbd_gsi, virtio_net_gsi); 346 { 347 let mut ptable = proc::PROCESSES.lock(); 348 let created = ptable 349 .allocate(&mut allocator) 350 .expect("Failed to create process 0"); 351 assert!(created.pid().raw() == 0, "First process must be pid 0"); 352 ptable.start(created).expect("Created -> Ready"); 353 } 354 { 355 let memory_map = arch::boot::memory_map(); 356 let reserved = cap::boot_untyped::build_reserved_regions(); 357 let boot_untypeds = { 358 let ptable = proc::PROCESSES.lock(); 359 let mut pool = cap::pool::POOL.lock_after(&ptable); 360 cap::boot_untyped::create_boot_untypeds(memory_map, &reserved, &mut pool) 361 }; 362 363 cap::boot_untyped::store_metadata(boot_untypeds); 364 } 365 crate::test_harness::run_all(); 366 } 367 368 #[cfg(not(lancer_test))] 369 { 370 phase_begin!(proc); 371 372 fn extract_filename(path: &[u8]) -> &[u8] { 373 let last_slash = (0..path.len()).rev().find(|&i| path[i] == b'/'); 374 match last_slash { 375 Some(pos) => &path[pos + 1..], 376 None => path, 377 } 378 } 379 380 let modules = arch::boot::modules().unwrap_or(&[]); 381 show!(proc, "{} modules available", modules.len()); 382 383 let init_file = modules 384 .iter() 385 .find(|file| { 386 let filename = extract_filename(file.path().to_bytes()); 387 filename.len() == 4 && filename.iter().zip(b"init").all(|(a, b)| a == b) 388 }) 389 .expect("init module not found"); 390 391 let init_pid = { 392 let mut ptable = proc::PROCESSES.lock(); 393 let created = ptable 394 .allocate(&mut allocator) 395 .expect("failed to create init process"); 396 let pid = created.pid(); 397 ptable.start(created).expect("Created -> Ready"); 398 drop(ptable); 399 400 let data = 401 unsafe { core::slice::from_raw_parts(init_file.addr(), init_file.size() as usize) }; 402 proc::loader::spawn_module(pid, data, &mut allocator).expect("init module load failed"); 403 { 404 let mut ptable = proc::PROCESSES.lock(); 405 let exec = ptable.exec_mut(pid).expect("init pid missing"); 406 exec.set_name(b"init"); 407 exec.saved_context.rdi = u64::MAX; 408 exec.seal_context(); 409 } 410 pid 411 }; 412 413 show!(proc, "init loaded as pid {}", init_pid.raw()); 414 phase_end!(proc); 415 416 phase_begin!(fb); 417 match arch::boot::framebuffer() { 418 Some(fb) => show!( 419 fb, 420 "{}x{} {}bpp pitch {}", 421 fb.width(), 422 fb.height(), 423 fb.bpp(), 424 fb.pitch() 425 ), 426 None => show!(fb, "no framebuffer available"), 427 } 428 phase_end!(fb); 429 430 phase_begin!(boot); 431 proc::bootstrap::bootstrap_self_cap(init_pid, 10).expect("init self-cap failed"); 432 433 { 434 const KERNEL_FRAME_RESERVE: usize = 5120; 435 let reserve_base = allocator 436 .allocate_contiguous(KERNEL_FRAME_RESERVE) 437 .expect("kernel frame reserve allocation failed"); 438 439 let memory_map = arch::boot::memory_map(); 440 let reserved = cap::boot_untyped::build_reserved_regions(); 441 let boot_untypeds = { 442 let ptable = proc::PROCESSES.lock(); 443 let mut pool = cap::pool::POOL.lock_after(&ptable); 444 cap::boot_untyped::create_boot_untypeds(memory_map, &reserved, &mut pool) 445 }; 446 447 cap::boot_untyped::seal_bitmap(&boot_untypeds); 448 449 (0..KERNEL_FRAME_RESERVE).for_each(|i| { 450 let phys = x86_64::PhysAddr::new(reserve_base.as_u64() + (i as u64) * 4096); 451 allocator.deallocate_frame( 452 x86_64::structures::paging::PhysFrame::containing_address(phys), 453 ); 454 }); 455 456 let total_bytes: u64 = boot_untypeds 457 .as_slice() 458 .iter() 459 .filter(|u| !u.is_device) 460 .map(|u| 1u64 << u.size_bits) 461 .fold(0u64, u64::saturating_add); 462 show!( 463 boot, 464 "{} boot untypeds, {}MB usable exported, {}KB kernel reserve", 465 boot_untypeds.len(), 466 total_bytes / (1024 * 1024), 467 (KERNEL_FRAME_RESERVE * 4096) / 1024, 468 ); 469 470 cap::boot_untyped::install_boot_untypeds(init_pid, &boot_untypeds) 471 .expect("install boot untypeds"); 472 cap::boot_untyped::store_metadata(boot_untypeds); 473 } 474 475 proc::address_space::sync_kernel_entries(); 476 phase_end!(boot); 477 478 let boot_end = tsc::read_tsc(); 479 let boot_cycles = boot_end - boot_start; 480 481 dashboard::dash().transition_to_streaming(); 482 show!( 483 boot, 484 "complete {} cycles {}ns", 485 boot_cycles, 486 tsc::cycles_to_ns(boot_cycles) 487 ); 488 489 sched::rescue(); 490 } 491}