diff options
-rw-r--r-- | bunny/Cargo.toml | 1 | ||||
-rw-r--r-- | bunny/src/ap_boot.s | 115 | ||||
-rw-r--r-- | bunny/src/lapic.rs | 206 | ||||
-rw-r--r-- | bunny/src/main.rs | 111 | ||||
-rw-r--r-- | bunny/src/println.rs | 2 | ||||
-rw-r--r-- | bunny/src/uefi.rs | 6 |
6 files changed, 188 insertions, 253 deletions
diff --git a/bunny/Cargo.toml b/bunny/Cargo.toml index 5f6ae9d..e8a5617 100644 --- a/bunny/Cargo.toml +++ b/bunny/Cargo.toml @@ -3,6 +3,7 @@ name = "bunny" version = "0.1.0" authors = ["Nick Shipp <nick@shipp.ninja>"] build = "build.rs" +edition = "2018" [dependencies] efi = { path = "libefi" } diff --git a/bunny/src/ap_boot.s b/bunny/src/ap_boot.s new file mode 100644 index 0000000..5058b00 --- /dev/null +++ b/bunny/src/ap_boot.s @@ -0,0 +1,115 @@ +bits 16 + +global ap_real_entry + +; CR3 bits +%define PROTECTED_MODE_ENABLE (1) +%define MONITOR_COPROCESSOR (1 << 1) +%define PAGING (1 << 31) + +; CR4 bits +%define DE (1 << 3) +%define PAE (1 << 5) +%define OS_FXSR (1 << 9) +%define OS_XMM_FPEXC (1 << 10) +%define OS_XSAVE (1 << 18) + +%define MSR_EFER (0xc0000080) + +; EFER bits +; 100100000001 +%define SYSCALL (1) +%define LONG (1 << 8) +%define NX (1 << 11) + +org 0x8000 +ap_real_entry: + cli + cld + + xor ax, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Only one core can execute this trampoline at a time or shit gets weird. + ; This is a shared-memory mutex to force that. + mov bx, 0x6000 + mov cl, 1 +.wait_for_lock: + ; compare AL (0) with [0x6000]. If not equal, loop. If equal, load CL (1) + ; into [0x6000] and continue. + pause + xor al, al + lock cmpxchg byte [ds:bx], cl + jnz short .wait_for_lock + + inc bx + ; increment n_aps (0x6001) + inc byte [ds:bx] + movzx cx, byte [ds:bx] + + ; Set the A20 line to enable protected-mode addressing ("fast" method) + in al, 0x92 + or al, 2 + out 0x92, al + + ; Duplicate BSP's CR3 + mov eax, dword [bsp_cr3] + mov cr3, eax + + ; Set NXE (NX enable), LME (long mode enable), and SCE (syscall enable) in EFER. + xor edx, edx + mov eax, (SYSCALL|LONG|NX) + mov ecx, MSR_EFER + wrmsr + + mov eax, (OS_XSAVE|OS_XMM_FPEXC|OS_FXSR|PAE|DE) + mov cr4, eax + + mov eax, (PAGING|MONITOR_COPROCESSOR|PROTECTED_MODE_ENABLE) + mov cr0, eax + + ; Load long mode IDT + lidt [lmidt] + + ; Load long mode GDT + lgdt [lmgdt] + + jmp 0x0008:ap_long_entry + + + +bits 64 +ap_long_entry: + + ; Enable AVX, SSE and x87 + mov edx, 0 + mov eax, 7 + mov ecx, 0 + xsetbv + + ; unlock AP initialization mutex + mov rax, 0x6000 + mov byte [rax], 0 + +.loop: + hlt + jmp .loop + +align 8 +lmgdt_base: + dq 0x0000000000000000 ; Null descriptor + dq 0x00209a0000000000 ; 64-bit, present, code + dq 0x0000920000000000 ; Present, data r/w + +lmgdt: + dw (lmgdt - lmgdt_base) - 1 + dq lmgdt_base + +bsp_cr3: + dd 0 +lmidt: + dw 0 + dq 0 diff --git a/bunny/src/lapic.rs b/bunny/src/lapic.rs index 86d7a43..c1bfce6 100644 --- a/bunny/src/lapic.rs +++ b/bunny/src/lapic.rs @@ -1,176 +1,45 @@ -use interrupt::IRQ_APIC_LVT_ERROR; +use crate::IRQ_APIC_LVT_ERROR; use x86_64::registers::model_specific::Msr; -/* - * See: Intel SDM Table 10-1: Local APIC Register Address Map - */ -/* -#[allow(unused, non_snake_case)] -#[repr(C)] -struct MappedLocalApic { - _r0000: Ro<u32>, - _pad00: [u32; 3], - - _r0010: Ro<u32>, - _pad01: [u32; 3], - - id: Ro<u32>, /* 0020 */ - _pad02: [u32; 3], - - version: Ro<u32>, /* 0030 */ - _pad03: [u32; 3], - - _r0040: Ro<u32>, - _pad04: [u32; 3], - - _r0050: Ro<u32>, - _pad05: [u32; 3], - - _r0060: Ro<u32>, - _pad06: [u32; 3], - - _r0070: Ro<u32>, - _pad07: [u32; 3], - - task_priority: Ro<u32>, /* 0080 */ - _pad08: [u32; 3], - - arbitration_priority: Ro<u32>, /* 0090 */ - _pad09: [u32; 3], - - processor_priority: Ro<u32>, /* 00A0 */ - _pad10: [u32; 3], - - eoi: Ro<u32>, /* 00B0 */ - _pad11: [u32; 3], - - remote_read: Ro<u32>, /* 00C0 */ - _pad12: [u32; 3], - - logical_destination: Ro<u32>, /* 00D0 */ - _pad13: [u32; 3], - - destination_format: Ro<u32>, /* 00E0 */ - _pad14: [u32; 3], - - spurious_interrupt_vector: Rw<u32>, /* 00F0 */ - _pad15: [u32; 3], - - in_service: Ro<[u32; 32]>, /* 0100-0170 */ - - trigger_mode: Ro<[u32; 32]>, /* 0180-01F0 */ - - interrupt_request: Ro<[u32; 32]>, /* 0200-0270 */ - - error_status: Ro<u32>, /* 0280 */ - _pad16: [u32; 3], - - _r0290: Ro<u32>, - _pad17: [u32; 3], - - _r02A0: Ro<u32>, - _pad18: [u32; 3], - - _r02B0: Ro<u32>, - _pad19: [u32; 3], - - _r02C0: Ro<u32>, - _pad20: [u32; 3], - - _r02D0: Ro<u32>, - _pad21: [u32; 3], - - _r02E0: Ro<u32>, - _pad22: [u32; 3], - - lvt_corrected_machine_check_interrupt: Rw<u32>, /* 02F0 */ - _pad23: [u32; 3], - - interrupt_command_register: Rw<[u32; 8]>, /* 0300-0310 */ - - lvt_timer: Rw<u32>, /* 0320 */ - _pad25: [u32; 3], - - lvt_thermal_sensor: Rw<u32>, /* 0330 */ - _pad26: [u32; 3], - - lvt_performance_monitoring_counters: Rw<u32>, /* 0340 */ - _pad27: [u32; 3], - - lvt_lint0: Rw<u32>, /* 0350 */ - _pad28: [u32; 3], - - lvt_lint1: Rw<u32>, /* 0360 */ - _pad29: [u32; 3], - - lvt_error: Rw<u32>, /* 0370 */ - _pad30: [u32; 3], - - initial_count: Rw<u32>, /* 0380 */ - _pad31: [u32; 3], - - current_count: Ro<u32>, /* 0390 */ - _pad32: [u32; 3], - - _r03A0: Ro<u32>, - _pad33: [u32; 3], - - _r03B0: Ro<u32>, - _pad34: [u32; 3], - - _r03C0: Ro<u32>, - _pad35: [u32; 3], - - _r03D0: Ro<u32>, - _pad36: [u32; 3], - - divide_conf: Rw<u32>, /* 03E0 */ - _pad37: [u32; 3], - - _r03F0: Ro<u32>, -} -*/ - #[allow(unused)] struct LocalVectorTable { - cmci: Msr, - timer: Msr, - thermal_sensor: Msr, - perfmon: Msr, - lint0: Msr, - lint1: Msr, - error: Msr, + cmci: Msr, + timer: Msr, + thermal_sensor: Msr, + perfmon: Msr, + lint0: Msr, + lint1: Msr, + error: Msr, } #[allow(unused)] pub struct LocalApic { - /* raw: &'map mut MappedLocalApic, */ - id: Msr, - version: Msr, - task_priority: Msr, - processor_priority: Msr, - eoi: Msr, - logical_destination: Msr, - spurious_interrupt_vector: Msr, - in_service: [Msr; 8], - trigger_mode: [Msr; 8], - interrupt_request: [Msr; 8], - error_status: Msr, - local_vector_table: LocalVectorTable, - interrupt_command: Msr, - initial_count: Msr, - current_count: Msr, - divide_config: Msr, - self_ipi: Msr, + id: Msr, + version: Msr, + task_priority: Msr, + processor_priority: Msr, + eoi: Msr, + logical_destination: Msr, + spurious_interrupt_vector: Msr, + in_service: [Msr; 8], + trigger_mode: [Msr; 8], + interrupt_request: [Msr; 8], + error_status: Msr, + local_vector_table: LocalVectorTable, + interrupt_command: Msr, + initial_count: Msr, + current_count: Msr, + divide_config: Msr, + self_ipi: Msr, } #[allow(unused)] #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiDestination { - JustMe = 0b01 << 18, - All = 0b10 << 18, + JustMe = 0b01 << 18, + All = 0b10 << 18, AllButMe = 0b11 << 18, } @@ -178,7 +47,7 @@ pub enum IpiDestination { #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiTriggerMode { - Edge = 0 << 15, + Edge = 0 << 15, Level = 1 << 15, } @@ -187,21 +56,22 @@ pub enum IpiTriggerMode { #[repr(u32)] pub enum IpiLevel { Deassert = 0 << 14, - Assert = 1 << 14, + Assert = 1 << 14, } #[allow(unused)] #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiDeliveryMode { - Fixed = 0b000 << 8, + Fixed = 0b000 << 8, LowestPriority = 0b001 << 8, - Smi = 0b010 << 8, - Nmi = 0b100 << 8, - Init = 0b101 << 8, - StartUp = 0b110 << 8, + Smi = 0b010 << 8, + Nmi = 0b100 << 8, + Init = 0b101 << 8, + StartUp = 0b110 << 8, } +#[allow(unused)] impl LocalApic { pub fn init() -> LocalApic { const MSR_BASE: u32 = 0x800; @@ -303,11 +173,5 @@ impl LocalApic { | (delivery_mode as u64) | (vector as u64)); } - - dprintln!("IPI: 0x{:x}", (dest as u64) - | (trigger_mode as u64) - | (level as u64) - | (delivery_mode as u64) - | (vector as u64)); } } diff --git a/bunny/src/main.rs b/bunny/src/main.rs index 21fa9cc..e7f5c70 100644 --- a/bunny/src/main.rs +++ b/bunny/src/main.rs @@ -21,40 +21,14 @@ 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::*; +use self::interrupt::*; +use self::lapic::*; +use self::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"); - } +const NUM_CORES: u8 = 4; - 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"); - } - } -} +static mut SYSTEM_TABLE: *const SystemTable = 0 as *const SystemTable; #[allow(improper_ctypes)] extern "C" { @@ -62,6 +36,7 @@ extern "C" { 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; @@ -91,79 +66,63 @@ pub extern fn efi_main(_handle: Handle, systab: &SystemTable) -> ! { 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"); - + /* 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()) }; - 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); + /* Read initial CR3 register to pass off to other cores */ 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..]); + 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 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"); + ptr::write_volatile(0x6000 as *mut u16, 0); } - /* Disable the PICs to prepare for APIC/IOAPIC */ + /* Disable the PICs to prepare for other cores */ unsafe { io::out::<u8>(io::PIC1_DATA, io::PIC_DISABLE); io::out::<u8>(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"); + /* INIT-SIPI-SIPI: Brings up other cores */ 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"); + + /* + * Wait for cores to get themselves figured out, retrying the SIPI + * broadcast until everyone is accounted for. + */ let mut n_aps: u8 = 0; - // let mut ap_lock: u8; - while n_aps < 3 { - dprintln!("SIPI"); + while n_aps < NUM_CORES-1 { bsp_apic.send_ipi(IpiDestination::AllButMe, IpiTriggerMode::Edge, IpiLevel::Assert, @@ -171,18 +130,12 @@ pub extern fn efi_main(_handle: Handle, systab: &SystemTable) -> ! { 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); - // } } + dprintln!("All cores online"); + + /* All good, turn interrupts back on and idle */ interrupts::enable(); loop { diff --git a/bunny/src/println.rs b/bunny/src/println.rs index db59e79..6e17cd2 100644 --- a/bunny/src/println.rs +++ b/bunny/src/println.rs @@ -2,7 +2,7 @@ macro_rules! print { ($($arg:tt)*) => ({ use core::fmt::Write; - unsafe { (&*::SYSTEM_TABLE.as_ref().unwrap().con_out) } + unsafe { (&*crate::SYSTEM_TABLE.as_ref().unwrap().con_out) } .write_fmt(format_args!($($arg)*)) .expect("could not write to console"); }); diff --git a/bunny/src/uefi.rs b/bunny/src/uefi.rs index a4a76d1..e23e668 100644 --- a/bunny/src/uefi.rs +++ b/bunny/src/uefi.rs @@ -4,8 +4,9 @@ use efi::types::Status; extern "win64" fn _wakeup(_ev: &Event, _ctxt: &u64) { } +#[allow(unused)] pub fn sleep(microseconds: u64) { - let bs = &unsafe { &*::SYSTEM_TABLE }.boot_services; + let bs = &unsafe { &*crate::SYSTEM_TABLE }.boot_services; dprintln!("create_event"); let mut ev = &Event::default(); @@ -32,8 +33,9 @@ pub fn sleep(microseconds: u64) { bs.close_event(ev).unwrap(); } +#[allow(unused)] pub fn dump_mem_map() -> Result<usize, Status> { - let bs = &unsafe { &*::SYSTEM_TABLE }.boot_services; + let bs = &unsafe { &*crate::SYSTEM_TABLE }.boot_services; let mmap = bs.get_memory_map()?; |