#![feature(lang_items, panic_info_message, abi_x86_interrupt, core_intrinsics, asm, link_llvm_intrinsics, int_to_from_bytes)] #![no_std] #![no_main] extern crate efi; extern crate x86_64; extern crate volatile; #[macro_use] mod println; mod interrupt; mod lapic; mod io; mod uefi; mod inttraits; use core::panic::PanicInfo; use core::ptr; use core::slice; use efi::types::Handle; use efi::SystemTable; use x86_64::instructions::interrupts; use self::interrupt::*; use self::lapic::*; use self::inttraits::*; const NUM_CORES: u8 = 4; static mut SYSTEM_TABLE: *const SystemTable = 0 as *const SystemTable; #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.rdtsc"] fn rdtsc() -> i64; } /* Awful way of busy-waiting some constant-ish number of cycle-ish intervals */ fn busy() { let init = unsafe { rdtsc() } as u64; let future = init + 1_000_000; let mut now = init; while now < future { now = unsafe { rdtsc() } as u64; } } #[no_mangle] pub extern fn efi_main(_handle: Handle, systab: &SystemTable) -> ! { /* * Disable interrupts to avoid noise generated before we actually * have anything to do *with* interrupts */ interrupts::disable(); /* * Save EFI system table ptr to globally accessible location. * MUST do this before calling println!(), or just about anything else. */ unsafe { SYSTEM_TABLE = systab; } println!("FUZZY BUNNIES {}", env!("CARGO_PKG_VERSION")); println!("efi_main @ 0x{:x}", efi_main as *const u8 as usize); /* Set up basic exception handlers */ register_handlers(); /* Set up AP bootstrap (real->long transition) code */ let code = include_bytes!(concat!(env!("OUT_DIR"), "/ap_boot.bin")); let dest = unsafe { /* Copy the code to somewhere in the first 1MB of memory */ slice::from_raw_parts_mut(0x8000 as *mut u8, code.len()) }; dest.copy_from_slice(code); /* Read initial CR3 register to pass off to other cores */ let cr3_val: u64; unsafe { asm!("mov $0, cr3" : "=r" (cr3_val) ::: "intel"); } let idtr = interrupt::descriptor(); /* Fill in CR3 (u32) and IDTR (u16; u64) at the end of the bootstrap code */ dest[code.len()-14..code.len()-10] .copy_from_slice(&(cr3_val as u32).as_bytes()); dest[code.len()-10..code.len()-8] .copy_from_slice(&idtr.0.as_bytes()); dest[code.len()-8..] .copy_from_slice(&idtr.1.as_bytes()); /* Initialize AP mutex (unlocked) and count (0) */ unsafe { ptr::write_volatile(0x6000 as *mut u16, 0); } /* Disable the PICs to prepare for other cores */ unsafe { io::out::(io::PIC1_DATA, io::PIC_DISABLE); io::out::(io::PIC2_DATA, io::PIC_DISABLE); } let mut bsp_apic = LocalApic::init(); bsp_apic.enable(); /* INIT-SIPI-SIPI: Brings up other cores */ bsp_apic.send_ipi(IpiDestination::AllButMe, IpiTriggerMode::Edge, IpiLevel::Assert, IpiDeliveryMode::Init, 0); busy(); /* * Wait for cores to get themselves figured out, retrying the SIPI * broadcast until everyone is accounted for. */ let mut n_aps: u8 = 0; while n_aps < NUM_CORES-1 { bsp_apic.send_ipi(IpiDestination::AllButMe, IpiTriggerMode::Edge, IpiLevel::Assert, IpiDeliveryMode::StartUp, 0x08); busy(); n_aps = unsafe { ptr::read_volatile(0x6001 as *const u8) }; } dprintln!("All cores online"); /* All good, turn interrupts back on and idle */ interrupts::enable(); loop { unsafe { asm!("hlt"); } } } #[lang = "eh_personality"] #[no_mangle] pub extern fn eh_personality() { } #[no_mangle] #[panic_handler] pub extern fn panic_impl(pi: &PanicInfo) -> ! { println!("!!! PANIC !!!"); if let Some(loc) = pi.location() { println!("in file {}:{}:{}", loc.file(), loc.line(), loc.column()); } if let Some(msg) = pi.message() { println!("{}", msg); } loop {} }