Finish x86 SMP startup. Support timer & IPI.

- Remove smp, apic mod.
  Instead, use new bootloader & apic crate.
- Disable PIC & PIT.
  Instead, use IOAPIC & APIC Timer.
master
WangRunji 6 years ago
parent 6cdf505f62
commit f1771f8ef2

91
kernel/Cargo.lock generated

@ -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)" = "<none>"
"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)" = "<none>"
"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)" = "<none>"
"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)" = "<none>"
"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"

@ -4,7 +4,6 @@ version = "0.1.0"
authors = ["Runji Wang <wangrunji0408@163.com>"]
[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"

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

@ -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`
@ -8,3 +11,17 @@ pub unsafe fn exit_in_qemu(error_code: u8) -> ! {
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();
}

@ -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<IoApic> = Mutex::new(unsafe{IoApic::new()});
}
// IO APIC MMIO structure: write reg, then read or write data.
#[repr(C)]
struct IoApicMmio {
reg: Mmio<u32>,
pad: [Mmio<u32>; 3],
data: Mmio<u32>,
}
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
}
}

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

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

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

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

@ -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") {
// Use IOAPIC instead of PIC
pic::disable();
apic::init();
} else {
pic::init();
}
pit::init();
// Use APIC Timer instead of PIT
// pit::init();
serial::init();
keyboard::init();
}

@ -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时自动切换栈的地址

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

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

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

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

@ -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<MemorySet> = 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
}
Loading…
Cancel
Save