diff options
Diffstat (limited to 'bunny')
| -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"); -    } - -    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"); -            } -        } +const NUM_CORES: u8 = 4; -        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()?; | 
