aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bunny/Cargo.toml1
-rw-r--r--bunny/src/ap_boot.s115
-rw-r--r--bunny/src/lapic.rs206
-rw-r--r--bunny/src/main.rs111
-rw-r--r--bunny/src/println.rs2
-rw-r--r--bunny/src/uefi.rs6
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()?;