#![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 x86_64::registers::control; use interrupt::*; use lapic::*; use inttraits::*; static mut SYSTEM_TABLE: *const SystemTable = 0 as *const SystemTable; fn serial_poke() { const PORT: u16 = 0x3f8; unsafe { asm!("out dx, al" :: "{dx}"(PORT+1), "{al}"(0x00) :: "intel", "volatile"); asm!("out dx, al" :: "{dx}"(PORT+3), "{al}"(0x80) :: "intel", "volatile"); asm!("out dx, al" :: "{dx}"(PORT+0), "{al}"(0x03) :: "intel", "volatile"); asm!("out dx, al" :: "{dx}"(PORT+1), "{al}"(0x00) :: "intel", "volatile"); asm!("out dx, al" :: "{dx}"(PORT+3), "{al}"(0x03) :: "intel", "volatile"); asm!("out dx, al" :: "{dx}"(PORT+2), "{al}"(0xc7) :: "intel", "volatile"); asm!("out dx, al" :: "{dx}"(PORT+4), "{al}"(0x0b) :: "intel", "volatile"); } for c in b"###*-*-*-*-*-*-*-*-*-*-###\r\n\r\n" { let mut status: u8 = 0; while status & 0x20 == 0 { unsafe { asm!("in al, dx" : "={al}"(status) : "{dx}"(PORT+5) :: "intel", "volatile"); } } unsafe { asm!("out dx, al" :: "{dx}"(PORT), "{al}"(c) :: "intel", "volatile"); } } } #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.rdtsc"] fn rdtsc() -> i64; } 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); dprintln!("CR0: {:x?}, CR3: {:x?}", control::Cr0::read(), control::Cr3::read()); /* Set up basic exception handlers */ register_handlers(); // serial_poke(); // unsafe { asm!("hlt"); } // let _mapkey = uefi::dump_mem_map().expect("Unable to read UEFI memory map"); let code = include_bytes!(concat!(env!("OUT_DIR"), "/ap_boot.bin")); let dest = unsafe { slice::from_raw_parts_mut(0x8000 as *mut u8, code.len()) }; let idtr = interrupt::descriptor(); dprintln!("copy {} bytes from 0x{:x} to 0x{:x}", code.len(), code.as_ptr() as usize, dest.as_ptr() as usize); dest.copy_from_slice(code); let cr3_val: u64; unsafe { asm!("mov $0, cr3" : "=r" (cr3_val) ::: "intel"); } 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()); dprintln!("patched: {:x?}", &dest[code.len()-14..]); unsafe { ptr::write_volatile(0x6000 as *mut u64, 0); ptr::write_volatile(0x6008 as *mut u64, 0); ptr::write_volatile(0x600c as *mut u64, 0); ptr::write_volatile(0x6010 as *mut u64, 0); asm!("mfence; lfence"); } /* Disable the PICs to prepare for APIC/IOAPIC */ unsafe { io::out::(io::PIC1_DATA, io::PIC_DISABLE); io::out::(io::PIC2_DATA, io::PIC_DISABLE); } let mut bsp_apic = LocalApic::init(); println!("APIC ID: {}, VERSION: {}", bsp_apic.id(), bsp_apic.version()); bsp_apic.enable(); dprintln!("APIC enabled"); /* INIT-SIPI-SIPI */ dprintln!("INIT ASSERT"); bsp_apic.send_ipi(IpiDestination::AllButMe, IpiTriggerMode::Edge, IpiLevel::Assert, IpiDeliveryMode::Init, 0); busy(); // println!("INIT LEVEL DEASSERT"); // bsp_apic.send_ipi(IpiDestination::AllButMe, // IpiTriggerMode::Level, // IpiLevel::Deassert, // IpiDeliveryMode::Init, // 0); // busy(); println!("SIPI spam"); let mut n_aps: u8 = 0; // let mut ap_lock: u8; while n_aps < 3 { dprintln!("SIPI"); bsp_apic.send_ipi(IpiDestination::AllButMe, IpiTriggerMode::Edge, IpiLevel::Assert, IpiDeliveryMode::StartUp, 0x08); busy(); unsafe { asm!("mfence; lfence"); } // ap_lock = unsafe { ptr::read_volatile(0x6000 as *const u8) }; n_aps = unsafe { ptr::read_volatile(0x6001 as *const u8) }; // println!("ap_lock: {}, n_aps: {}", ap_lock, n_aps); // { // let ap_stats = unsafe { slice::from_raw_parts(0x6002 as *const u8, n_aps as usize) }; // println!("stat: {:x?}", ap_stats); // } } 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 {} }