Impl lapic linking C code. Fix build.rs in macOS.

toolchain_update
WangRunji 7 years ago
parent b549d08724
commit 21d97418d6

@ -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");
}

@ -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<ACPI_Result, ACPI_Error> {
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];

@ -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

@ -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);
}

@ -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();
}
}

@ -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);
}
}
}

@ -0,0 +1,7 @@
mod lapic;
mod ioapic;
pub fn init(lapic_addr: *const ()) {
self::lapic::init(lapic_addr);
// self::ioapic::init();
}

@ -1,5 +1,5 @@
pub mod vga;
pub mod acpi;
pub mod ioapic;
pub mod apic;
pub mod mp;
pub mod serial;

@ -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");

@ -1,3 +0,0 @@
int square(int x) {
return x * x;
}
Loading…
Cancel
Save