From df083e306a53e6a45a5730e7059032be43cc75ff Mon Sep 17 00:00:00 2001 From: Nick Shipp Date: Sun, 30 Sep 2018 17:05:47 -0400 Subject: Dirty rotten commit full of badness Milestone: Got SMP cores booting and into long mode. The rest is all trash, but maybe trash worth a future archaeological dig. --- bunny/src/main.rs | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 bunny/src/main.rs (limited to 'bunny/src/main.rs') diff --git a/bunny/src/main.rs b/bunny/src/main.rs new file mode 100644 index 0000000..21fa9cc --- /dev/null +++ b/bunny/src/main.rs @@ -0,0 +1,211 @@ +#![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 {} +} -- cgit v1.2.3-54-g00ecf