diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index d8de26e..83938d6 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -1,3 +1,13 @@ +[[package]] +name = "apic" +version = "0.1.0" +source = "git+https://github.com/wangrunji0408/APIC-Rust#5002b7de801178bef0635e7fe399ce513f04cbf9" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bare-metal" version = "0.2.3" @@ -32,11 +42,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bootloader" version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/wangrunji0408/bootloader#d53b01de2fb8c0b3793ebf2d8ec1d56180dc71d4" dependencies = [ + "apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)", "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -86,7 +97,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -135,7 +146,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "raw-cpuid" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -148,7 +169,7 @@ name = "remove_dir_all" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -160,10 +181,31 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "simple-filesystem" version = "0.0.1" -source = "git+https://github.com/wangrunji0408/SimpleFileSystem-Rust#ca10d11264c85932e95e6c7c29e8b10c91ae0720" +source = "git+https://github.com/wangrunji0408/SimpleFileSystem-Rust#e26f14c55f2b5e767ac7055bab874d039fbe1f05" dependencies = [ "bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)", "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -203,23 +245,25 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ucore" version = "0.1.0" dependencies = [ + "apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)", "bbl 0.1.0", "bit-allocator 0.1.0", "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bootloader 0.3.1 (git+https://github.com/wangrunji0408/bootloader)", "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "riscv 0.3.0", "simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)", @@ -228,7 +272,7 @@ dependencies = [ "ucore-memory 0.1.0", "ucore-process 0.1.0", "volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -260,7 +304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "version_check" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -270,7 +314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -287,9 +331,18 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "x86" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x86_64" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -313,11 +366,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)" = "" "checksum bare-metal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1bdcf9294ed648c7cd29b11db06ea244005aeef50ae8f605b1a3af2940bf8f92" "checksum bit-vec 0.5.0 (git+https://github.com/AltSysrq/bit-vec.git)" = "" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum bootloader 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1721ced9efc102309bc218c7934d642f60567858faf8d5dd90c0cc6722d97b9" +"checksum bootloader 0.3.1 (git+https://github.com/wangrunji0408/bootloader)" = "" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" @@ -332,8 +386,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" +"checksum raw-cpuid 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41219962ecab392f1e68db9e7ebd972800d4045a128cc23462b384e8c312cde1" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum simple-filesystem 0.0.1 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)" = "" "checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" "checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" @@ -343,11 +401,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" -"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum volatile 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37c5d76c0f40ba4f8ac10ec4717d4e98ce3e58c5607eea36e9464226fc5e0a95" -"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum x86_64 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "466c2002e38edde7ebbaae6656793d4f71596634971c7e8cbf7afa4827968445" +"checksum x86 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "841e1ca5a87068718a2a26f2473c6f93cf3b8119f9778fa0ae4b39b664d9e66a" +"checksum x86_64 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a7e95a2813e20d24546c2b29ecc6df55cfde30c983df69eeece0b179ca9d68ac" "checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" "checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 0afa030..1027eb3 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors = ["Runji Wang "] [features] -use_apic = [] link_user_program = [] no_bbl = [] @@ -32,8 +31,12 @@ ucore-process = { path = "../crate/process" } simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" } [target.'cfg(target_arch = "x86_64")'.dependencies] -bootloader = "0.3" -x86_64 = "0.2.11" +bootloader = { git = "https://github.com/wangrunji0408/bootloader" } +apic = { git = "https://github.com/wangrunji0408/APIC-Rust" } +#bootloader = { path = "../crate/bootloader" } +#apic = { path = "../crate/apic" } +x86_64 = "0.2" +raw-cpuid = "6.0" redox_syscall = "0.1" uart_16550 = "0.1" diff --git a/kernel/Makefile b/kernel/Makefile index 0053184..919ab75 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -36,7 +36,7 @@ qemu_opts := \ -device isa-debug-exit endif ifeq ($(arch), riscv32) -qemu_opts := -machine virt -kernel $(bin) -nographic +qemu_opts := -machine virt -kernel $(bin) -nographic -smp 4 endif ifdef board diff --git a/kernel/src/arch/x86_64/cpu.rs b/kernel/src/arch/x86_64/cpu.rs index 8e93cca..18a63d2 100644 --- a/kernel/src/arch/x86_64/cpu.rs +++ b/kernel/src/arch/x86_64/cpu.rs @@ -1,3 +1,6 @@ +use super::apic::{LocalApic, XApic}; +use super::raw_cpuid::CpuId; + /// Exit qemu /// See: https://wiki.osdev.org/Shutdown /// Must run qemu with `-device isa-debug-exit` @@ -7,4 +10,18 @@ pub unsafe fn exit_in_qemu(error_code: u8) -> ! { assert_eq!(error_code & 1, 1, "error code should be odd"); Port::new(0x501).write((error_code - 1) / 2); unreachable!() +} + +pub fn id() -> usize { + CpuId::new().get_feature_info().unwrap().initial_local_apic_id() as usize +} + +pub fn send_ipi(cpu_id: u8) { + let mut lapic = unsafe { XApic::new(0xffffff00_fee00000) }; + unsafe { lapic.send_ipi(cpu_id, 0x30); } // TODO: Find a IPI trap num +} + +pub fn init() { + let mut lapic = unsafe { XApic::new(0xffffff00_fee00000) }; + lapic.cpu_init(); } \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/ioapic.rs b/kernel/src/arch/x86_64/driver/apic/ioapic.rs deleted file mode 100644 index 48e7d35..0000000 --- a/kernel/src/arch/x86_64/driver/apic/ioapic.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! 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 -/// See also picirq.c. - -use super::super::redox_syscall::io::{Io, Mmio}; -use bit_field::BitField; -use arch::interrupt::consts::T_IRQ0; -use spin::Mutex; - -pub fn init() -{ - let mut ioapic = IOAPIC.lock(); - - // Mark all interrupts edge-triggered, active high, disabled, - // and not routed to any CPUs. - for i in 0.. ioapic.maxintr() + 1 { - ioapic.write_irq(i, RedirectionEntry::DISABLED, 0); - } - info!("ioapic: init end"); -} - -const IOAPIC_ADDRESS : u32 = 0xFEC00000; // Default physical address of IO APIC - -const REG_ID : u8 = 0x00; // Register index: ID -const REG_VER : u8 = 0x01; // Register index: version -const REG_TABLE : u8 = 0x10; // Redirection table base - -// The redirection table starts at REG_TABLE and uses -// two registers to configure each interrupt. -// The first (low) register in a pair contains configuration bits. -// The second (high) register contains a bitmask telling which -// CPUs can serve that interrupt. - -bitflags! { - struct RedirectionEntry: u32 { - const DISABLED = 0x00010000; // Interrupt disabled - const LEVEL = 0x00008000; // Level-triggered (vs edge-) - const ACTIVELOW = 0x00002000; // Active low (vs high) - const LOGICAL = 0x00000800; // Destination is CPU id (vs APIC ID) - const NONE = 0x00000000; - } -} - -lazy_static! { - pub static ref IOAPIC: Mutex = Mutex::new(unsafe{IoApic::new()}); -} - -// IO APIC MMIO structure: write reg, then read or write data. -#[repr(C)] -struct IoApicMmio { - reg: Mmio, - pad: [Mmio; 3], - data: Mmio, -} - -pub struct IoApic { - mmio: &'static mut IoApicMmio -} - -impl IoApic { - unsafe fn new() -> Self { - IoApic { mmio: &mut *(IOAPIC_ADDRESS as *mut IoApicMmio) } - } - fn read(&mut self, reg: u8) -> u32 - { - self.mmio.reg.write(reg as u32); - self.mmio.data.read() - } - fn write(&mut self, reg: u8, data: u32) - { - self.mmio.reg.write(reg as u32); - self.mmio.data.write(data); - } - fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8) - { - self.write(REG_TABLE+2*irq, (T_IRQ0 + irq) as u32 | flags.bits()); - self.write(REG_TABLE+2*irq+1, (dest as u32) << 24); - } - pub fn enable(&mut self, irq: u8, cpunum: u8) - { - info!("ioapic: enable irq {} @ cpu{}", irq, cpunum); - // Mark interrupt edge-triggered, active high, - // enabled, and routed to the given cpunum, - // which happens to be that cpu's APIC ID. - self.write_irq(irq, RedirectionEntry::NONE, cpunum); - } - fn id(&mut self) -> u8 { - self.read(REG_ID).get_bits(24..28) as u8 - } - fn version(&mut self) -> u8 { - self.read(REG_VER).get_bits(0..8) as u8 - } - fn maxintr(&mut self) -> u8 { - self.read(REG_VER).get_bits(16..24) as u8 - } -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/lapic.c b/kernel/src/arch/x86_64/driver/apic/lapic.c deleted file mode 100644 index b01b1b8..0000000 --- a/kernel/src/arch/x86_64/driver/apic/lapic.c +++ /dev/null @@ -1,165 +0,0 @@ -// The local APIC manages internal (non-I/O) interrupts. -// See Chapter 8 & Appendix C of Intel processor manual volume 3. - -typedef unsigned int uint; -typedef unsigned char uchar; -typedef unsigned short ushort; - -static inline void -outb(ushort port, uchar data) -{ - asm volatile("out %0,%1" : : "a" (data), "d" (port)); -} - -#define KERNBASE 0xFFFFFF0000000000 // First kernel virtual address -#define P2V(a) (((void *) (a)) + KERNBASE) - -#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); -} - -// Acknowledge interrupt. -void -lapiceoi(void) -{ - if(lapic) - lapicw(EOI, 0); -} - -// Spin for a given number of microseconds. -// On real hardware would want to tune this dynamically. -void -microdelay(int us) -{ -} - -#define CMOS_PORT 0x70 -#define CMOS_RETURN 0x71 - -// Start additional processor running entry code at addr. -// See Appendix B of MultiProcessor Specification. -void -lapicstartap(uchar apicid, uint addr) -{ - int i; - ushort *wrv; - - // "The BSP must initialize CMOS shutdown code to 0AH - // and the warm reset vector (DWORD based at 40:67) to point at - // the AP startup code prior to the [universal startup algorithm]." - outb(CMOS_PORT, 0xF); // offset 0xF is shutdown code - outb(CMOS_PORT+1, 0x0A); - wrv = (ushort*)P2V((0x40<<4 | 0x67)); // Warm reset vector - wrv[0] = 0; - wrv[1] = addr >> 4; - - // "Universal startup algorithm." - // Send INIT (level-triggered) interrupt to reset other CPU. - lapicw(ICRHI, apicid<<24); - lapicw(ICRLO, INIT | LEVEL | ASSERT); - microdelay(200); - lapicw(ICRLO, INIT | LEVEL); - microdelay(10000); - - // Send startup IPI (twice!) to enter code. - // Regular hardware is supposed to only accept a STARTUP - // when it is in the halted state due to an INIT. So the second - // should be ignored, but it is part of the official Intel algorithm. - for(i = 0; i < 2; i++){ - lapicw(ICRHI, apicid<<24); - lapicw(ICRLO, STARTUP | (addr>>12)); - microdelay(200); - } -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/lapic.rs b/kernel/src/arch/x86_64/driver/apic/lapic.rs deleted file mode 100644 index b70e776..0000000 --- a/kernel/src/arch/x86_64/driver/apic/lapic.rs +++ /dev/null @@ -1,46 +0,0 @@ -extern { - //noinspection RsStaticConstNaming - static mut lapic: *const (); - fn lapicinit(); // must set `lapic` first - fn lapiceoi(); // ack - fn lapicstartap(apicid: u8, addr: u32); -} - -pub fn set_addr(lapic_addr: usize) { - unsafe { -// lapic = lapic_addr; - } -} - -pub fn init() { - warn!("lapic::init use C lib"); - unsafe { -// lapicinit(); - } - info!("lapic: init end"); -} - -pub fn ack(_irq: u8) { - unsafe { -// lapiceoi(); - } -} - -pub fn start_ap(apicid: u8, addr: u32) { - warn!("lapic::start_ap use C lib"); - unsafe { -// lapicstartap(apicid, addr); - } -} - -pub fn lapic_id() -> u8 { - 0 -// unsafe{ -// if lapic.is_null() { -// warn!("lapic is null. return lapic id = 0"); -// return 0; -// } -// let ptr = (lapic as *const u32).offset(0x0020 / 4); -// (ptr.read_volatile() >> 24) as u8 -// } -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/apic/local_apic.rs b/kernel/src/arch/x86_64/driver/apic/local_apic.rs deleted file mode 100644 index edb228b..0000000 --- a/kernel/src/arch/x86_64/driver/apic/local_apic.rs +++ /dev/null @@ -1,116 +0,0 @@ -use core::intrinsics::{volatile_load, volatile_store}; -use x86::cpuid::CpuId; -use x86::msr::*; - -use memory::Frame; -use paging::{ActivePageTable, PhysAddr, 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(PhysAddr::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/kernel/src/arch/x86_64/driver/apic/mod.rs b/kernel/src/arch/x86_64/driver/apic/mod.rs deleted file mode 100644 index 3cf6af8..0000000 --- a/kernel/src/arch/x86_64/driver/apic/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub use self::ioapic::IOAPIC; -pub use self::lapic::{ack, start_ap, lapic_id}; - -mod lapic; -mod ioapic; - -pub fn init() { - assert_has_not_been_called!("apic::init must be called only once"); - use consts::KERNEL_OFFSET; - self::lapic::set_addr(KERNEL_OFFSET + 0xfee00000); - self::lapic::init(); - self::ioapic::init(); -} - -pub fn other_init() { - self::lapic::init(); -} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/driver/mod.rs b/kernel/src/arch/x86_64/driver/mod.rs index 5064353..e2450c6 100644 --- a/kernel/src/arch/x86_64/driver/mod.rs +++ b/kernel/src/arch/x86_64/driver/mod.rs @@ -1,7 +1,6 @@ extern crate syscall as redox_syscall; pub mod vga; -pub mod apic; pub mod serial; pub mod pic; pub mod keyboard; @@ -11,13 +10,12 @@ pub mod ide; pub fn init() { assert_has_not_been_called!(); - if cfg!(feature = "use_apic") { - pic::disable(); - apic::init(); - } else { - pic::init(); - } - pit::init(); + // Use IOAPIC instead of PIC + pic::disable(); + + // Use APIC Timer instead of PIT + // pit::init(); + serial::init(); keyboard::init(); } \ No newline at end of file diff --git a/kernel/src/arch/x86_64/gdt.rs b/kernel/src/arch/x86_64/gdt.rs index 20d0034..620e543 100644 --- a/kernel/src/arch/x86_64/gdt.rs +++ b/kernel/src/arch/x86_64/gdt.rs @@ -1,5 +1,4 @@ use alloc::boxed::Box; -use arch::driver::apic::lapic_id; use consts::MAX_CPU_NUM; use core::fmt; use core::fmt::Debug; @@ -50,7 +49,7 @@ pub fn init() { load_tss(TSS_SELECTOR); } - CPUS[lapic_id() as usize].call_once(|| + CPUS[super::cpu::id() as usize].call_once(|| Mutex::new(Cpu { gdt, tss: unsafe { &mut *tss } })); } @@ -67,7 +66,7 @@ pub struct Cpu { impl Cpu { pub fn current() -> MutexGuard<'static, Cpu> { - CPUS[lapic_id() as usize].try().unwrap().lock() + CPUS[super::cpu::id()].try().unwrap().lock() } /// 设置从Ring3跳到Ring0时,自动切换栈的地址 diff --git a/kernel/src/arch/x86_64/interrupt/handler.rs b/kernel/src/arch/x86_64/interrupt/handler.rs index 9d5b5aa..a0369a4 100644 --- a/kernel/src/arch/x86_64/interrupt/handler.rs +++ b/kernel/src/arch/x86_64/interrupt/handler.rs @@ -72,7 +72,7 @@ global_asm!(include_str!("vector.asm")); #[no_mangle] pub extern fn rust_trap(tf: &mut TrapFrame) { - trace!("Interrupt: {:#x}", tf.trap_num); + trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, super::super::cpu::id()); // Dispatch match tf.trap_num as u8 { T_BRKPT => breakpoint(), @@ -88,11 +88,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { IRQ_IDE => ide(), _ => panic!("Invalid IRQ number: {}", irq), } - #[cfg(feature = "use_apic")] - use arch::driver::apic::ack; - #[cfg(not(feature = "use_apic"))] - use arch::driver::pic::ack; - ack(irq); + super::ack(irq); } T_SWITCH_TOK => to_kernel(tf), T_SWITCH_TOU => to_user(tf), diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs index a1b9ecb..2e62cdb 100644 --- a/kernel/src/arch/x86_64/interrupt/mod.rs +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -1,5 +1,4 @@ use x86_64; -use arch::driver::{apic::IOAPIC, pic}; pub mod consts; mod handler; @@ -7,6 +6,8 @@ mod trapframe; pub use self::trapframe::*; pub use self::handler::*; +use super::apic::*; +use consts::KERNEL_OFFSET; #[inline(always)] pub unsafe fn enable() { @@ -39,9 +40,12 @@ pub fn no_interrupt(f: impl FnOnce()) { #[inline(always)] pub fn enable_irq(irq: u8) { - if cfg!(feature = "use_apic") { - IOAPIC.lock().enable(irq, 0); - } else { - pic::enable_irq(irq); - } + let mut ioapic = unsafe { IoApic::new(KERNEL_OFFSET + IOAPIC_ADDR as usize) }; + ioapic.enable(irq, 0); +} + +#[inline(always)] +pub fn ack(irq: u8) { + let mut lapic = unsafe { XApic::new(KERNEL_OFFSET + LAPIC_ADDR) }; + lapic.eoi(); } \ No newline at end of file diff --git a/kernel/src/arch/x86_64/memory.rs b/kernel/src/arch/x86_64/memory.rs index 54bd283..e0fcf30 100644 --- a/kernel/src/arch/x86_64/memory.rs +++ b/kernel/src/arch/x86_64/memory.rs @@ -1,14 +1,15 @@ use bit_allocator::BitAlloc; use consts::KERNEL_OFFSET; // Depends on kernel -use memory::{FRAME_ALLOCATOR, init_heap}; +use memory::{FRAME_ALLOCATOR, init_heap, active_table}; use super::{BootInfo, MemoryRegionType}; use ucore_memory::PAGE_SIZE; -use ucore_memory::paging::PageTable; +use ucore_memory::paging::*; pub fn init(boot_info: &BootInfo) { assert_has_not_been_called!("memory::init must be called only once"); init_frame_allocator(boot_info); + init_device_vm_map(); init_heap(); info!("memory: init end"); } @@ -22,3 +23,11 @@ fn init_frame_allocator(boot_info: &BootInfo) { } } } + +fn init_device_vm_map() { + let mut page_table = active_table(); + // IOAPIC + page_table.map(KERNEL_OFFSET + 0xfec00000, 0xfec00000).update(); + // LocalAPIC + page_table.map(KERNEL_OFFSET + 0xfee00000, 0xfee00000).update(); +} diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index d1868f7..64b66af 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -1,6 +1,10 @@ extern crate bootloader; +extern crate apic; +extern crate raw_cpuid; use self::bootloader::bootinfo::{BootInfo, MemoryRegionType}; +use core::sync::atomic::*; +use consts::KERNEL_OFFSET; pub mod driver; pub mod cpu; @@ -8,14 +12,22 @@ pub mod interrupt; pub mod paging; pub mod gdt; pub mod idt; -// TODO: Move multi-core init to bootloader -//pub mod smp; pub mod memory; pub mod io; +static AP_CAN_INIT: AtomicBool = ATOMIC_BOOL_INIT; + /// The entry point of kernel #[no_mangle] // don't mangle the name of this function pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { + let cpu_id = cpu::id(); + println!("Hello world! from CPU {}!", cpu_id); + + if cpu_id != 0 { + while !AP_CAN_INIT.load(Ordering::Relaxed) {} + other_start(); + } + // First init log mod, so that we can print log info. ::logging::init(); info!("Hello world!"); @@ -30,20 +42,20 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { // Now heap is available gdt::init(); + cpu::init(); + driver::init(); + AP_CAN_INIT.store(true, Ordering::Relaxed); + ::kmain(); } -/// The entry point for another processors -#[no_mangle] -pub extern "C" fn other_main() -> ! { +/// The entry point for other processors +fn other_start() -> ! { idt::init(); gdt::init(); - driver::apic::other_init(); - let cpu_id = driver::apic::lapic_id(); -// let ms = unsafe { smp::notify_started(cpu_id) }; - println!("Hello world! from CPU {}!", cpu_id); + cpu::init(); // unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault loop {} } \ No newline at end of file diff --git a/kernel/src/arch/x86_64/smp.rs b/kernel/src/arch/x86_64/smp.rs deleted file mode 100644 index 1d39a7b..0000000 --- a/kernel/src/arch/x86_64/smp.rs +++ /dev/null @@ -1,41 +0,0 @@ -use arch::driver::{acpi::AcpiResult, apic::start_ap}; -use consts::MAX_CPU_NUM; -use core::ptr::{read_volatile, write_volatile}; -use memory::*; -use x86_64::registers::control::Cr3; - -pub const ENTRYOTHER_ADDR: usize = 0x7000; - -pub fn start_other_cores(acpi: &AcpiResult) { - let args = unsafe { &mut *(0x8000 as *mut EntryArgs).offset(-1) }; - for i in 1 .. acpi.cpu_num { - let apic_id = acpi.cpu_acpi_ids[i as usize]; - let ms = MemorySet::new(); - *args = EntryArgs { - kstack: ms.kstack_top() as u64, - page_table: Cr3::read().0.start_address().as_u64() as u32, - stack: args as *const _ as u32, // just enough stack to get us to entry64mp - }; - unsafe { MS = Some(ms); } - start_ap(apic_id, ENTRYOTHER_ADDR as u32); - while unsafe { !read_volatile(&STARTED[i as usize]) } {} - } -} - -#[repr(C)] -#[derive(Debug)] -struct EntryArgs { - kstack: u64, - page_table: u32, - stack: u32, -} - -static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; -static mut MS: Option = None; - -pub unsafe fn notify_started(cpu_id: u8) -> MemorySet { - write_volatile(&mut STARTED[cpu_id as usize], true); - let ms = MS.take().unwrap(); - ms.activate(); - ms -} \ No newline at end of file