diff --git a/build.rs b/build.rs index 7615bed..add2486 100644 --- a/build.rs +++ b/build.rs @@ -1,11 +1,16 @@ extern crate cc; +use std::process::Command; fn main() { - let mut build = cc::Build::new(); - - let compiler = if build.get_compiler().is_like_clang() - { "x86_64-elf-gcc" } else {"gcc"}; - build.compiler(compiler) - .file("src/test.c") - .compile("cobj"); + let output = Command::new("uname").output() + .expect("failed to get uname"); + let compiler = match output.stdout.as_slice() { + b"Darwin\n" => "x86_64-elf-gcc", + b"Linux\n" => "gcc", + _ => panic!("unknown os") + }; + cc::Build::new() + .compiler(compiler) + .file("src/arch/x86_64/driver/apic/lapic.c") + .compile("cobj"); } \ No newline at end of file diff --git a/src/arch/x86_64/driver/acpi/mod.rs b/src/arch/x86_64/driver/acpi/mod.rs index 913ef5a..2567aba 100644 --- a/src/arch/x86_64/driver/acpi/mod.rs +++ b/src/arch/x86_64/driver/acpi/mod.rs @@ -35,10 +35,10 @@ const PHYSICAL_MEMORY_LIMIT: u32 = 0x80000000; #[derive(Debug)] pub struct ACPI_Result { - cpu_num: u8, - cpu_acpi_ids: [u8; MAX_CPU_NUM], - ioapic_id: u8, - lapic_addr: u32, + pub cpu_num: u8, + pub cpu_acpi_ids: [u8; MAX_CPU_NUM], + pub ioapic_id: u8, + pub lapic_addr: *const (), } #[derive(Debug)] @@ -48,7 +48,7 @@ pub enum ACPI_Error { } fn config_smp(madt: &'static madt) -> Result { - let lapic_addr = madt.LapicAddress; + let lapic_addr = madt.LapicAddress as *const (); let mut cpu_num = 0u8; let mut cpu_acpi_ids: [u8; MAX_CPU_NUM] = [0; MAX_CPU_NUM]; diff --git a/src/arch/x86_64/driver/ioapic.rs b/src/arch/x86_64/driver/apic/ioapic.rs similarity index 98% rename from src/arch/x86_64/driver/ioapic.rs rename to src/arch/x86_64/driver/apic/ioapic.rs index 992c53b..f1efdc6 100644 --- a/src/arch/x86_64/driver/ioapic.rs +++ b/src/arch/x86_64/driver/apic/ioapic.rs @@ -1,4 +1,4 @@ -// Migrate from xv6 ioapic.c +//! Migrate from xv6 ioapic.c /// The I/O APIC manages hardware interrupts for an SMP system. /// http://www.intel.com/design/chipsets/datashts/29056601.pdf diff --git a/src/arch/x86_64/driver/apic/lapic.c b/src/arch/x86_64/driver/apic/lapic.c new file mode 100644 index 0000000..d4655fc --- /dev/null +++ b/src/arch/x86_64/driver/apic/lapic.c @@ -0,0 +1,100 @@ +// The local APIC manages internal (non-I/O) interrupts. +// See Chapter 8 & Appendix C of Intel processor manual volume 3. + +typedef unsigned int uint; + +#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ + +#define IRQ_TIMER 0 +#define IRQ_KBD 1 +#define IRQ_COM1 4 +#define IRQ_IDE 14 +#define IRQ_ERROR 19 +#define IRQ_SPURIOUS 31 + +// Local APIC registers, divided by 4 for use as uint[] indices. +#define ID (0x0020/4) // ID +#define VER (0x0030/4) // Version +#define TPR (0x0080/4) // Task Priority +#define EOI (0x00B0/4) // EOI +#define SVR (0x00F0/4) // Spurious Interrupt Vector + #define ENABLE 0x00000100 // Unit Enable +#define ESR (0x0280/4) // Error Status +#define ICRLO (0x0300/4) // Interrupt Command + #define INIT 0x00000500 // INIT/RESET + #define STARTUP 0x00000600 // Startup IPI + #define DELIVS 0x00001000 // Delivery status + #define ASSERT 0x00004000 // Assert interrupt (vs deassert) + #define DEASSERT 0x00000000 + #define LEVEL 0x00008000 // Level triggered + #define BCAST 0x00080000 // Send to all APICs, including self. + #define BUSY 0x00001000 + #define FIXED 0x00000000 +#define ICRHI (0x0310/4) // Interrupt Command [63:32] +#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER) + #define X1 0x0000000B // divide counts by 1 + #define PERIODIC 0x00020000 // Periodic +#define PCINT (0x0340/4) // Performance Counter LVT +#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0) +#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1) +#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR) + #define MASKED 0x00010000 // Interrupt masked +#define TICR (0x0380/4) // Timer Initial Count +#define TCCR (0x0390/4) // Timer Current Count +#define TDCR (0x03E0/4) // Timer Divide Configuration + +volatile uint *lapic; // Initialized in mp.c + +static void +lapicw(int index, int value) +{ + lapic[index] = value; + lapic[ID]; // wait for write to finish, by reading +} +//PAGEBREAK! + +void +lapicinit(void) +{ + if(!lapic) + return; + + // Enable local APIC; set spurious interrupt vector. + lapicw(SVR, ENABLE | (T_IRQ0 + IRQ_SPURIOUS)); + + // The timer repeatedly counts down at bus frequency + // from lapic[TICR] and then issues an interrupt. + // If xv6 cared more about precise timekeeping, + // TICR would be calibrated using an external time source. + lapicw(TDCR, X1); + lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER)); + lapicw(TICR, 10000000); + + // Disable logical interrupt lines. + lapicw(LINT0, MASKED); + lapicw(LINT1, MASKED); + + // Disable performance counter overflow interrupts + // on machines that provide that interrupt entry. + if(((lapic[VER]>>16) & 0xFF) >= 4) + lapicw(PCINT, MASKED); + + // Map error interrupt to IRQ_ERROR. + lapicw(ERROR, T_IRQ0 + IRQ_ERROR); + + // Clear error status register (requires back-to-back writes). + lapicw(ESR, 0); + lapicw(ESR, 0); + + // Ack any outstanding interrupts. + lapicw(EOI, 0); + + // Send an Init Level De-Assert to synchronise arbitration ID's. + lapicw(ICRHI, 0); + lapicw(ICRLO, BCAST | INIT | LEVEL); + while(lapic[ICRLO] & DELIVS) + ; + + // Enable interrupts on the APIC (but not on the processor). + lapicw(TPR, 0); +} \ No newline at end of file diff --git a/src/arch/x86_64/driver/apic/lapic.rs b/src/arch/x86_64/driver/apic/lapic.rs new file mode 100644 index 0000000..1d9a538 --- /dev/null +++ b/src/arch/x86_64/driver/apic/lapic.rs @@ -0,0 +1,14 @@ +extern { + static mut lapic: *const (); + fn lapicinit(); // must set `lapic` first +} + +pub fn init(lapic_addr: *const ()) { + debug!("WARNING: lapic::init use C lib"); + unsafe { + lapic = lapic_addr; + debug!("lapic = {:?}", lapic); + unimplemented!(); + lapicinit(); + } +} \ No newline at end of file diff --git a/src/arch/x86_64/driver/apic/local_apic.rs b/src/arch/x86_64/driver/apic/local_apic.rs new file mode 100644 index 0000000..0b5c175 --- /dev/null +++ b/src/arch/x86_64/driver/apic/local_apic.rs @@ -0,0 +1,116 @@ +use core::intrinsics::{volatile_load, volatile_store}; +use x86::cpuid::CpuId; +use x86::msr::*; + +use memory::Frame; +use paging::{ActivePageTable, PhysicalAddress, Page, VirtualAddress}; +use paging::entry::EntryFlags; + +pub static mut LOCAL_APIC: LocalApic = LocalApic { + address: 0, + x2: false +}; + +pub unsafe fn init(active_table: &mut ActivePageTable) { + LOCAL_APIC.init(active_table); +} + +pub unsafe fn init_ap() { + LOCAL_APIC.init_ap(); +} + +/// Local APIC +pub struct LocalApic { + pub address: usize, + pub x2: bool +} + +impl LocalApic { + unsafe fn init(&mut self, active_table: &mut ActivePageTable) { + self.address = (rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000) + ::KERNEL_OFFSET; + self.x2 = CpuId::new().get_feature_info().unwrap().has_x2apic(); + + if ! self.x2 { + let page = Page::containing_address(VirtualAddress::new(self.address)); + let frame = Frame::containing_address(PhysicalAddress::new(self.address - ::KERNEL_OFFSET)); + let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE); + result.flush(active_table); + } + + self.init_ap(); + } + + unsafe fn init_ap(&mut self) { + if self.x2 { + wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10); + wrmsr(IA32_X2APIC_SIVR, 0x100); + } else { + self.write(0xF0, 0x100); + } + } + + unsafe fn read(&self, reg: u32) -> u32 { + volatile_load((self.address + reg as usize) as *const u32) + } + + unsafe fn write(&mut self, reg: u32, value: u32) { + volatile_store((self.address + reg as usize) as *mut u32, value); + } + + pub fn id(&self) -> u32 { + if self.x2 { + unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } + } else { + unsafe { self.read(0x20) } + } + } + + pub fn version(&self) -> u32 { + if self.x2 { + unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } + } else { + unsafe { self.read(0x30) } + } + } + + pub fn icr(&self) -> u64 { + if self.x2 { + unsafe { rdmsr(IA32_X2APIC_ICR) } + } else { + unsafe { + (self.read(0x310) as u64) << 32 | self.read(0x300) as u64 + } + } + } + + pub fn set_icr(&mut self, value: u64) { + if self.x2 { + unsafe { wrmsr(IA32_X2APIC_ICR, value); } + } else { + unsafe { + while self.read(0x300) & 1 << 12 == 1 << 12 {} + self.write(0x310, (value >> 32) as u32); + self.write(0x300, value as u32); + while self.read(0x300) & 1 << 12 == 1 << 12 {} + } + } + } + + pub fn ipi(&mut self, apic_id: usize) { + let mut icr = 0x4040; + if self.x2 { + icr |= (apic_id as u64) << 32; + } else { + icr |= (apic_id as u64) << 56; + } + self.set_icr(icr); + } + + pub unsafe fn eoi(&mut self) { + if self.x2 { + wrmsr(IA32_X2APIC_EOI, 0); + } else { + self.write(0xB0, 0); + } + } +} diff --git a/src/arch/x86_64/driver/apic/mod.rs b/src/arch/x86_64/driver/apic/mod.rs new file mode 100644 index 0000000..d931d6f --- /dev/null +++ b/src/arch/x86_64/driver/apic/mod.rs @@ -0,0 +1,7 @@ +mod lapic; +mod ioapic; + +pub fn init(lapic_addr: *const ()) { + self::lapic::init(lapic_addr); + // self::ioapic::init(); +} \ No newline at end of file diff --git a/src/arch/x86_64/driver/mod.rs b/src/arch/x86_64/driver/mod.rs index 626481e..881ad79 100644 --- a/src/arch/x86_64/driver/mod.rs +++ b/src/arch/x86_64/driver/mod.rs @@ -1,5 +1,5 @@ pub mod vga; pub mod acpi; -pub mod ioapic; +pub mod apic; pub mod mp; pub mod serial; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0eb5b52..ca17c65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,32 +47,32 @@ mod arch; #[no_mangle] pub extern "C" fn rust_main(multiboot_information_address: usize) { // ATTENTION: we have a very small stack and no guard page - test!(extern_fn); - test!(find_mp); - - let acpi = arch::driver::acpi::init(); - debug!("{:?}", acpi); - unimplemented!(); - - arch::driver::ioapic::init(); - io::init(); println!("Hello World{}", "!"); let boot_info = unsafe { multiboot2::load(multiboot_information_address) }; arch::init(); // set up guard page and map the heap pages - let mut memory_controller = memory::init(boot_info); - + let mut memory_controller = memory::init(boot_info); unsafe { HEAP_ALLOCATOR.lock().init(HEAP_START, HEAP_START + HEAP_SIZE); - } + } // initialize our IDT - interrupts::init(&mut memory_controller); + interrupts::init(&mut memory_controller); test!(global_allocator); test!(guard_page); + test!(find_mp); + + // TODO Build temp page map. Now page fault. + let acpi = arch::driver::acpi::init().expect("Failed to init ACPI"); + debug!("{:?}", acpi); + unimplemented!(); + + arch::driver::apic::init(acpi.lapic_addr); + io::init(); + test_end!(); } @@ -85,14 +85,6 @@ pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); mod test { - extern { - fn square(x: u32) -> u32; - } - - pub fn extern_fn() { - assert_eq!(unsafe{square(2)}, 4); - } - pub fn global_allocator() { for i in 0..10000 { format!("Some String"); diff --git a/src/test.c b/src/test.c deleted file mode 100644 index 59c6fdf..0000000 --- a/src/test.c +++ /dev/null @@ -1,3 +0,0 @@ -int square(int x) { - return x * x; -} \ No newline at end of file