aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2019-09-12 13:30:08 -0700
committerGravatar Gerd Zellweger <mail@gerdzellweger.com> 2019-09-12 13:30:08 -0700
commit6ce081418448d69847a4615157d3d8fa89fd188c (patch)
tree16886cc178cf00c097b7c003ed9dc363df563e19
parenta9eaf44e421bcdc4e9728ef1b33f90bb538310ec (diff)
downloadrust-x86-6ce081418448d69847a4615157d3d8fa89fd188c.tar.gz
rust-x86-6ce081418448d69847a4615157d3d8fa89fd188c.tar.zst
rust-x86-6ce081418448d69847a4615157d3d8fa89fd188c.zip
Add initial APIC code.
-rw-r--r--Cargo.toml1
-rw-r--r--src/apic/ioapic.rs101
-rw-r--r--src/apic/mod.rs97
-rw-r--r--src/apic/x2apic.rs86
-rw-r--r--src/apic/xapic.rs356
-rw-r--r--src/lib.rs4
-rw-r--r--src/segmentation.rs2
-rw-r--r--src/xapic.rs136
8 files changed, 645 insertions, 138 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 9f429fd..65b40b6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,6 +44,7 @@ serde_json = { version = "1.0.39", optional = true }
[dependencies]
bitflags = "1.*"
+bit_field = "0.10.0"
raw-cpuid = "7.0.*"
[dependencies.phf]
diff --git a/src/apic/ioapic.rs b/src/apic/ioapic.rs
new file mode 100644
index 0000000..5fad92f
--- /dev/null
+++ b/src/apic/ioapic.rs
@@ -0,0 +1,101 @@
+//! To control an I/O APIC.
+//!
+//! The IO APIC routes hardware interrupts to a local APIC.
+//!
+//! Figuring out which (bus,dev,fun,vector) maps to which I/O APIC
+//! entry can be a pain.
+
+use bit_field::BitField;
+use bitflags::bitflags;
+
+bitflags! {
+ /// 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.
+ struct RedirectionEntry: u32 {
+ /// Interrupt disabled
+ const DISABLED = 0x00010000;
+ /// Level-triggered (vs edge)
+ const LEVEL = 0x00008000;
+ /// Active low (vs high)
+ const ACTIVELOW = 0x00002000;
+ /// Destination is CPU id (vs APIC ID)
+ const LOGICAL = 0x00000800;
+ /// None
+ const NONE = 0x00000000;
+ }
+}
+
+pub struct IoApic {
+ reg: *mut u32,
+ data: *mut u32,
+}
+
+impl IoApic {
+ pub unsafe fn new(addr: usize) -> Self {
+ IoApic {
+ reg: addr as *mut u32,
+ data: (addr + 0x10) as *mut u32,
+ }
+ }
+ pub fn disable_all(&mut self) {
+ // Mark all interrupts edge-triggered, active high, disabled,
+ // and not routed to any CPUs.
+ for i in 0..self.supported_interrupts() {
+ self.write_irq(i, RedirectionEntry::DISABLED, 0);
+ }
+ }
+
+ unsafe fn read(&mut self, reg: u8) -> u32 {
+ self.reg.write_volatile(reg as u32);
+ self.data.read_volatile()
+ }
+
+ unsafe fn write(&mut self, reg: u8, data: u32) {
+ self.reg.write_volatile(reg as u32);
+ self.data.write_volatile(data);
+ }
+
+ fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8) {
+ unsafe {
+ 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) {
+ // 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);
+ }
+
+ pub fn id(&mut self) -> u8 {
+ unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
+ }
+
+ pub fn version(&mut self) -> u8 {
+ unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
+ }
+
+ /// Number of supported interrupts by this IO APIC.
+ ///
+ /// Max Redirection Entry = "how many IRQs can this I/O APIC handle - 1"
+ /// The -1 is silly so we add one back to it.
+ pub fn supported_interrupts(&mut self) -> u8 {
+ unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
+ }
+}
+
+/// Register index: ID
+const REG_ID: u8 = 0x00;
+
+/// Register index: version
+const REG_VER: u8 = 0x01;
+
+/// Redirection table base
+const REG_TABLE: u8 = 0x10;
+
+const T_IRQ0: u8 = 32;
diff --git a/src/apic/mod.rs b/src/apic/mod.rs
new file mode 100644
index 0000000..d3bbfc4
--- /dev/null
+++ b/src/apic/mod.rs
@@ -0,0 +1,97 @@
+//! Register information and driver to program xAPIC, X2APIC and I/O APIC
+
+pub mod ioapic;
+pub mod x2apic;
+pub mod xapic;
+
+#[repr(u64)]
+pub enum DeliveryMode {
+ /// Delivers the interrupt specified in the vector field to the target processor or processors.
+ Fixed = 0b000,
+ /// Same as fixed mode, except that the interrupt is delivered to the processor executing at the
+ /// lowest priority among the set of processors specified in the destination field. The ability
+ /// for a processor to send a lowest priority IPI is model specific and should be avoided by
+ /// BIOS and operating system software.
+ LowestPriority = 0b001,
+ /// Delivers an SMI interrupt to the target processor or processors.
+ /// The vector field must be programmed to 00H for future compatibility.
+ SMI = 0b010,
+ /// Reserved
+ _Reserved = 0b11,
+ /// Delivers an NMI interrupt to the target processor or processors.
+ /// The vector information is ignored.
+ NMI = 0b100,
+ /// Delivers an INIT request to the target processor or processors, which causes them to perform an INIT.
+ Init = 0b101,
+ /// Sends a special start-up IPI (called a SIPI) to the target processor or processors.
+ /// The vector typically points to a start-up routine that is part of the
+ /// BIOS boot-strap code (see Section 8.4, Multiple-Processor (MP) Initialization). I
+ /// PIs sent with this delivery mode are not automatically retried if the source
+ /// APIC is unable to deliver it. It is up to the software to deter- mine if the
+ /// SIPI was not successfully delivered and to reissue the SIPI if necessary.
+ StartUp = 0b110,
+}
+
+#[repr(u64)]
+pub enum DestinationMode {
+ Physical = 0,
+ Logical = 1,
+}
+
+#[repr(u64)]
+pub enum DeliveryStatus {
+ Idle = 0,
+ SendPending = 1,
+}
+
+#[repr(u64)]
+pub enum Level {
+ Deassert = 0,
+ Assert = 1,
+}
+
+#[repr(u64)]
+pub enum TriggerMode {
+ Edge = 0,
+ Level = 1,
+}
+
+#[repr(u64)]
+pub enum DestinationShorthand {
+ NoShorthand = 0b00,
+ Myself = 0b01,
+ AllIncludingSelf = 0b10,
+ AllExcludingSelf = 0b11,
+}
+
+pub struct Icr(u64);
+
+impl Icr {
+ pub fn new(
+ vector: u8,
+ destination: u8,
+ destination_shorthand: DestinationShorthand,
+ delivery_mode: DeliveryMode,
+ destination_mode: DestinationMode,
+ delivery_status: DeliveryStatus,
+ level: Level,
+ trigger_mode: TriggerMode,
+ ) -> Icr {
+ Icr((destination as u64) << 56
+ | (destination_shorthand as u64) << 18
+ | (trigger_mode as u64) << 15
+ | (level as u64) << 14
+ | (delivery_status as u64) << 12
+ | (destination_mode as u64) << 11
+ | (delivery_mode as u64) << 8
+ | (vector as u64))
+ }
+
+ pub fn lower(&self) -> u32 {
+ self.0 as u32
+ }
+
+ pub fn upper(&self) -> u32 {
+ (self.0 >> 32) as u32
+ }
+}
diff --git a/src/apic/x2apic.rs b/src/apic/x2apic.rs
new file mode 100644
index 0000000..7a98e7e
--- /dev/null
+++ b/src/apic/x2apic.rs
@@ -0,0 +1,86 @@
+//! x2APIC, the most recent APIC on x86 for large servers with more than 255 cores.
+use bit_field::BitField;
+
+use crate::msr::{
+ rdmsr, wrmsr, IA32_APIC_BASE, IA32_TSC_DEADLINE, IA32_X2APIC_APICID, IA32_X2APIC_ESR,
+ IA32_X2APIC_LVT_LINT0, IA32_X2APIC_LVT_TIMER, IA32_X2APIC_SELF_IPI, IA32_X2APIC_VERSION,
+};
+
+/// Represents an x2APIC driver instance.
+#[derive(Debug)]
+pub struct X2APIC {
+ /// Initial BASE msr register value.
+ base: u64,
+}
+
+impl X2APIC {
+ /// Create a new x2APIC driver object for the local core.
+ pub fn new() -> X2APIC {
+ unsafe {
+ X2APIC {
+ base: rdmsr(IA32_APIC_BASE),
+ }
+ }
+ }
+
+ /// Attach to APIC (enable x2APIC mode, initialize LINT0)
+ pub fn attach(&mut self) {
+ // Enable
+ unsafe {
+ self.base = rdmsr(IA32_APIC_BASE);
+ self.base.set_bit(10, true); // Enable x2APIC
+ self.base.set_bit(11, true); // Enable xAPIC
+ wrmsr(IA32_APIC_BASE, self.base);
+
+ //TODO: let mut lint0 = rdmsr(IA32_X2APIC_LVT_LINT0);
+ // TODO: Fix magic number
+ let lint0 = 1 << 16 | (1 << 15) | (0b111 << 8) | 0x20;
+ wrmsr(IA32_X2APIC_LVT_LINT0, lint0);
+
+ let _esr = rdmsr(IA32_X2APIC_ESR);
+ }
+ }
+
+ /// Detach from APIC (disable x2APIC and xAPIC mode).
+ pub fn detach(&mut self) {
+ unsafe {
+ self.base = rdmsr(IA32_APIC_BASE);
+ self.base.set_bit(10, false); // x2APIC
+ self.base.set_bit(11, false); // xAPIC
+ wrmsr(IA32_APIC_BASE, self.base);
+ }
+ }
+
+ /// Are we the BSP core?
+ pub fn bsp(&self) -> bool {
+ (self.base & (1 << 8)) > 0
+ }
+
+ /// Read local APIC ID.
+ pub fn id(&self) -> u32 {
+ unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
+ }
+
+ /// Read APIC version.
+ pub fn version(&self) -> u32 {
+ unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
+ }
+
+ /// Enable TSC timer
+ pub unsafe fn tsc_enable(&self) {
+ let mut lvt: u64 = rdmsr(IA32_X2APIC_LVT_TIMER);
+ lvt |= 0 << 17;
+ lvt |= 1 << 18;
+ wrmsr(IA32_X2APIC_LVT_TIMER, lvt);
+ }
+
+ /// Set tsc deadline.
+ pub unsafe fn tsc_set(&self, value: u64) {
+ wrmsr(IA32_TSC_DEADLINE, value);
+ }
+
+ /// Send an IPI to yourself.
+ pub unsafe fn send_self_ipi(&self, vector: u64) {
+ wrmsr(IA32_X2APIC_SELF_IPI, vector);
+ }
+}
diff --git a/src/apic/xapic.rs b/src/apic/xapic.rs
new file mode 100644
index 0000000..311452c
--- /dev/null
+++ b/src/apic/xapic.rs
@@ -0,0 +1,356 @@
+//! Information about the xAPIC for the local APIC.
+//!
+//! Table 10-1 Local APIC Register Address Map
+//! the MMIO base values are found in this file.
+
+use bit_field::BitField;
+
+/// Local APIC ID register. Read-only. See Section 10.12.5.1 for initial values.
+pub const XAPIC_ID: u32 = 0x020;
+
+/// Local APIC Version register. Read-only. Same version used in xAPIC mode and x2APIC mode.
+pub const XAPIC_VERSION: u32 = 0x030;
+
+/// Task Priority Register (TPR). Read/write. Bits 31:8 are reserved.
+pub const XAPIC_TPR: u32 = 0x080;
+
+/// Processor Priority Register (PPR). Read-only.
+pub const XAPIC_PPR: u32 = 0x0A0;
+
+/// EOI register. Write-only.
+pub const XAPIC_EOI: u32 = 0x0B0;
+
+/// Logical Destination Register (LDR). Read/write in xAPIC mode.
+pub const XAPIC_LDR: u32 = 0x0D0;
+
+/// Spurious Interrupt Vector Register (SVR). Read/write. See Section 10.9 for reserved bits.
+pub const XAPIC_SVR: u32 = 0x0F0;
+
+/// In-Service Register (ISR); bits 31:0. Read-only.
+pub const XAPIC_ISR0: u32 = 0x100;
+
+/// ISR bits 63:32. Read-only.
+pub const XAPIC_ISR1: u32 = 0x110;
+
+/// ISR bits 95:64. Read-only.
+pub const XAPIC_ISR2: u32 = 0x120;
+
+/// ISR bits 127:96. Read-only.
+pub const XAPIC_ISR3: u32 = 0x130;
+
+/// ISR bits 159:128. Read-only.
+pub const XAPIC_ISR4: u32 = 0x140;
+
+/// ISR bits 191:160. Read-only.
+pub const XAPIC_ISR5: u32 = 0x150;
+
+/// ISR bits 223:192. Read-only.
+pub const XAPIC_ISR6: u32 = 0x160;
+
+/// ISR bits 255:224. Read-only.
+pub const XAPIC_ISR7: u32 = 0x170;
+
+/// Trigger Mode Register (TMR); bits 31:0. Read-only.
+pub const XAPIC_TMR0: u32 = 0x180;
+
+/// TMR bits 63:32. Read-only.
+pub const XAPIC_TMR1: u32 = 0x190;
+
+/// TMR bits 95:64. Read-only.
+pub const XAPIC_TMR2: u32 = 0x1A0;
+
+/// TMR bits 127:96. Read-only.
+pub const XAPIC_TMR3: u32 = 0x1B0;
+
+/// TMR bits 159:128. Read-only.
+pub const XAPIC_TMR4: u32 = 0x1C0;
+
+/// TMR bits 191:160. Read-only.
+pub const XAPIC_TMR5: u32 = 0x1D0;
+
+/// TMR bits 223:192. Read-only.
+pub const XAPIC_TMR6: u32 = 0x1E0;
+
+/// TMR bits 255:224. Read-only.
+pub const XAPIC_TMR7: u32 = 0x1F0;
+
+/// Interrupt Request Register (IRR); bits 31:0. Read-only.
+pub const XAPIC_IRR0: u32 = 0x200;
+
+/// IRR bits 63:32. Read-only.
+pub const XAPIC_IRR1: u32 = 0x210;
+
+/// IRR bits 95:64. Read-only.
+pub const XAPIC_IRR2: u32 = 0x220;
+
+/// IRR bits 127:96. Read-only.
+pub const XAPIC_IRR3: u32 = 0x230;
+
+/// IRR bits 159:128. Read-only.
+pub const XAPIC_IRR4: u32 = 0x240;
+
+/// IRR bits 191:160. Read-only.
+pub const XAPIC_IRR5: u32 = 0x250;
+
+/// IRR bits 223:192. Read-only.
+pub const XAPIC_IRR6: u32 = 0x260;
+
+/// IRR bits 255:224. Read-only.
+pub const XAPIC_IRR7: u32 = 0x270;
+
+/// Error Status Register (ESR). Read/write. See Section 10.5.3.
+pub const XAPIC_ESR: u32 = 0x280;
+
+/// LVT CMCI register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_CMCI: u32 = 0x2F0;
+
+/// Interrupt Command Register (ICR). Read/write. See Figure 10-28 for reserved bits
+pub const XAPIC_ICR0: u32 = 0x300;
+
+/// Interrupt Command Register (ICR). Read/write. See Figure 10-28 for reserved bits
+pub const XAPIC_ICR1: u32 = 0x310;
+
+/// LVT Timer register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_TIMER: u32 = 0x320;
+
+/// LVT Thermal Sensor register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_THERMAL: u32 = 0x330;
+
+/// LVT Performance Monitoring register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_PMI: u32 = 0x340;
+
+/// LVT LINT0 register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_LINT0: u32 = 0x350;
+
+/// LVT LINT1 register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_LINT1: u32 = 0x360;
+
+/// LVT Error register. Read/write. See Figure 10-8 for reserved bits.
+pub const XAPIC_LVT_ERROR: u32 = 0x370;
+
+/// Initial Count register (for Timer). Read/write.
+pub const XAPIC_TIMER_INIT_COUNT: u32 = 0x380;
+
+/// Current Count register (for Timer). Read-only.
+pub const XAPIC_TIMER_CURRENT_COUNT: u32 = 0x390;
+
+/// Divide Configuration Register (DCR; for Timer). Read/write. See Figure 10-10 for reserved bits.
+pub const XAPIC_TIMER_DIV_CONF: u32 = 0x3E0;
+
+use super::*;
+use crate::msr::{rdmsr, wrmsr, IA32_APIC_BASE, IA32_TSC_DEADLINE};
+use core::intrinsics::{volatile_load, volatile_store};
+
+#[derive(Copy, Clone)]
+#[allow(dead_code, non_camel_case_types)]
+enum ApicRegister {
+ XAPIC_ID = XAPIC_ID as isize,
+ XAPIC_VERSION = XAPIC_VERSION as isize,
+ XAPIC_TPR = XAPIC_TPR as isize,
+ XAPIC_PPR = XAPIC_PPR as isize,
+ XAPIC_EOI = XAPIC_EOI as isize,
+ XAPIC_LDR = XAPIC_LDR as isize,
+ XAPIC_SVR = XAPIC_SVR as isize,
+ XAPIC_ISR0 = XAPIC_ISR0 as isize,
+ XAPIC_ISR1 = XAPIC_ISR1 as isize,
+ XAPIC_ISR2 = XAPIC_ISR2 as isize,
+ XAPIC_ISR3 = XAPIC_ISR3 as isize,
+ XAPIC_ISR4 = XAPIC_ISR4 as isize,
+ XAPIC_ISR5 = XAPIC_ISR5 as isize,
+ XAPIC_ISR6 = XAPIC_ISR6 as isize,
+ XAPIC_ISR7 = XAPIC_ISR7 as isize,
+ XAPIC_TMR0 = XAPIC_TMR0 as isize,
+ XAPIC_TMR1 = XAPIC_TMR1 as isize,
+ XAPIC_TMR2 = XAPIC_TMR2 as isize,
+ XAPIC_TMR3 = XAPIC_TMR3 as isize,
+ XAPIC_TMR4 = XAPIC_TMR4 as isize,
+ XAPIC_TMR5 = XAPIC_TMR5 as isize,
+ XAPIC_TMR6 = XAPIC_TMR6 as isize,
+ XAPIC_TMR7 = XAPIC_TMR7 as isize,
+ XAPIC_IRR0 = XAPIC_IRR0 as isize,
+ XAPIC_IRR1 = XAPIC_IRR1 as isize,
+ XAPIC_IRR2 = XAPIC_IRR2 as isize,
+ XAPIC_IRR3 = XAPIC_IRR3 as isize,
+ XAPIC_IRR4 = XAPIC_IRR4 as isize,
+ XAPIC_IRR5 = XAPIC_IRR5 as isize,
+ XAPIC_IRR6 = XAPIC_IRR6 as isize,
+ XAPIC_IRR7 = XAPIC_IRR7 as isize,
+ XAPIC_ESR = XAPIC_ESR as isize,
+ XAPIC_LVT_CMCI = XAPIC_LVT_CMCI as isize,
+ XAPIC_ICR0 = XAPIC_ICR0 as isize,
+ XAPIC_ICR1 = XAPIC_ICR1 as isize,
+ XAPIC_LVT_TIMER = XAPIC_LVT_TIMER as isize,
+ XAPIC_LVT_THERMAL = XAPIC_LVT_THERMAL as isize,
+ XAPIC_LVT_PMI = XAPIC_LVT_PMI as isize,
+ XAPIC_LVT_LINT0 = XAPIC_LVT_LINT0 as isize,
+ XAPIC_LVT_LINT1 = XAPIC_LVT_LINT1 as isize,
+ XAPIC_LVT_ERROR = XAPIC_LVT_ERROR as isize,
+ XAPIC_TIMER_INIT_COUNT = XAPIC_TIMER_INIT_COUNT as isize,
+ XAPIC_TIMER_CURRENT_COUNT = XAPIC_TIMER_CURRENT_COUNT as isize,
+ XAPIC_TIMER_DIV_CONF = XAPIC_TIMER_DIV_CONF as isize,
+}
+
+/// State for the XAPIC driver.
+#[derive(Debug)]
+pub struct XAPIC {
+ /// Reference to the xAPCI region
+ mmio_region: &'static mut [u32],
+ /// Initial APIC Base register value.
+ base: u64,
+}
+
+impl XAPIC {
+ /// Create a new xAPIC object for the local CPU.
+ ///
+ /// Pass the xAPCI region which is at XXX unless you have
+ /// relocated the region.
+ pub fn new(apic_region: &'static mut [u32]) -> XAPIC {
+ unsafe {
+ XAPIC {
+ mmio_region: apic_region,
+ base: rdmsr(IA32_APIC_BASE),
+ }
+ }
+ }
+
+ /// Attach driver to the xAPIC (enables device).
+ pub fn attach(&mut self) {
+ // Enable
+ unsafe {
+ self.base = rdmsr(IA32_APIC_BASE);
+ self.base.set_bit(11, true); // Enable xAPIC
+ wrmsr(IA32_APIC_BASE, self.base);
+ }
+ }
+
+ /// Detach driver form the xAPIC (disables device).
+ pub fn detach(&mut self) {
+ unsafe {
+ self.base = rdmsr(IA32_APIC_BASE);
+ self.base.set_bit(11, false); // Disable xAPIC
+ wrmsr(IA32_APIC_BASE, self.base);
+ }
+ }
+
+ /// Read a register from the MMIO region.
+ fn read(&self, offset: ApicRegister) -> u32 {
+ assert!(offset as usize % 4 == 0);
+ let index = offset as usize / 4;
+ unsafe { volatile_load(&self.mmio_region[index]) }
+ }
+
+ /// write a register in the MMIO region.
+ fn write(&mut self, offset: ApicRegister, val: u32) {
+ assert!(offset as usize % 4 == 0);
+ let index = offset as usize / 4;
+ unsafe { volatile_store(&mut self.mmio_region[index], val) }
+ }
+
+ /// Is this the bootstrap core?
+ pub fn bsp(&self) -> bool {
+ (self.base & (1 << 8)) > 0
+ }
+
+ /// Read local APIC ID.
+ pub fn id(&self) -> u32 {
+ self.read(ApicRegister::XAPIC_ID)
+ }
+
+ /// Read APIC version.
+ pub fn version(&self) -> u32 {
+ self.read(ApicRegister::XAPIC_VERSION)
+ }
+
+ /// Acknowledge interrupt delivery.
+ pub fn eoi(&mut self) {
+ self.write(ApicRegister::XAPIC_EOI, 0);
+ }
+
+ /// Enable TSC timer.
+ pub unsafe fn tsc_enable(&mut self) {
+ let mut lvt: u32 = self.read(ApicRegister::XAPIC_LVT_TIMER);
+ lvt.set_bit(17, false);
+ lvt.set_bit(18, true);
+ self.write(ApicRegister::XAPIC_LVT_TIMER, lvt);
+ }
+
+ /// Set TSC deadline value.
+ pub unsafe fn tsc_set(&self, value: u64) {
+ wrmsr(IA32_TSC_DEADLINE, value);
+ }
+
+ /// Send an init IPI.
+ ///
+ /// TODO: hard-coded target core.
+ /// TODO: Interface will change.
+ pub unsafe fn ipi_init(&mut self) {
+ let icr = Icr::new(
+ 0,
+ 1,
+ DestinationShorthand::NoShorthand,
+ DeliveryMode::Init,
+ DestinationMode::Physical,
+ DeliveryStatus::Idle,
+ Level::Assert,
+ TriggerMode::Level,
+ );
+ self.send_ipi(icr);
+ }
+
+ /// De-assert init IPI.
+ ///
+ /// TODO: hard-coded target core.
+ /// TODO: probably interface will change.
+ pub unsafe fn ipi_init_deassert(&mut self) {
+ let icr = Icr::new(
+ 0,
+ 0,
+ // INIT deassert is always sent to everyone, so we are supposed to specify:
+ DestinationShorthand::AllIncludingSelf,
+ DeliveryMode::Init,
+ DestinationMode::Physical,
+ DeliveryStatus::Idle,
+ Level::Deassert,
+ TriggerMode::Level,
+ );
+ self.send_ipi(icr);
+ }
+
+ /// Send startup IPI.
+ ///
+ /// TODO: hard-coded target core.
+ /// TODO: probably interface will change.
+ pub unsafe fn ipi_startup(&mut self, start_page: u8) {
+ let icr = Icr::new(
+ start_page,
+ 1,
+ DestinationShorthand::NoShorthand,
+ DeliveryMode::StartUp,
+ DestinationMode::Physical,
+ DeliveryStatus::Idle,
+ Level::Assert,
+ TriggerMode::Edge,
+ );
+ self.send_ipi(icr);
+ }
+
+ /// Send generic IPI.
+ unsafe fn send_ipi(&mut self, icr: Icr) {
+ self.write(ApicRegister::XAPIC_ESR, 0);
+ self.write(ApicRegister::XAPIC_ESR, 0);
+
+ // 10.6 ISSUING INTERPROCESSOR INTERRUPTS
+ self.write(ApicRegister::XAPIC_ICR1, icr.upper());
+ self.write(ApicRegister::XAPIC_ICR0, icr.lower());
+
+ loop {
+ let icr = self.read(ApicRegister::XAPIC_ICR0);
+ if (icr >> 12 & 0x1) == 0 {
+ break;
+ }
+ if self.read(ApicRegister::XAPIC_ESR) > 0 {
+ break;
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index de71f33..259167d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,6 @@
#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#![allow(stable_features)]
-#![feature(const_fn, asm, repr_transparent)]
+#![feature(const_fn, asm, repr_transparent, core_intrinsics)]
#![no_std]
#![cfg_attr(test, allow(unused_features))]
#![cfg_attr(all(test, feature = "vmtest"), feature(custom_test_frameworks))]
@@ -21,6 +21,7 @@ pub mod bits16;
pub mod bits32;
pub mod bits64;
+pub mod apic;
pub mod controlregs;
pub mod dtables;
pub mod io;
@@ -31,7 +32,6 @@ pub mod segmentation;
pub mod task;
pub mod time;
pub mod tlb;
-pub mod xapic;
#[cfg(feature = "performance-counter")]
pub mod perfcnt;
diff --git a/src/segmentation.rs b/src/segmentation.rs
index 0703544..d049b51 100644
--- a/src/segmentation.rs
+++ b/src/segmentation.rs
@@ -561,6 +561,8 @@ pub unsafe fn load_gs(sel: SegmentSelector) {
asm!("movw $0, %gs " :: "r" (sel.bits()) : "memory");
}
+pub use crate::current::segmentation::load_cs;
+
/// Returns the current value of the code segment register.
pub fn cs() -> SegmentSelector {
let segment: u16;
diff --git a/src/xapic.rs b/src/xapic.rs
deleted file mode 100644
index 27ec884..0000000
--- a/src/xapic.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-//! Information about the xAPIC and x2APIC mode for the local APIC.
-//!
-//! Table 10-1 Local APIC Register Address Map
-//! the MMIO base values are found in this file, for x2APIC MSR see msr.rs.
-
-/// Local APIC ID register. Read-only. See Section 10.12.5.1 for initial values.
-pub const XAPIC_ID: u32 = 0x020;
-
-/// Local APIC Version register. Read-only. Same version used in xAPIC mode and x2APIC mode.
-pub const XAPIC_VERSION: u32 = 0x030;
-
-/// Task Priority Register (TPR). Read/write. Bits 31:8 are reserved.
-pub const XAPIC_TPR: u32 = 0x080;
-
-/// Processor Priority Register (PPR). Read-only.
-pub const XAPIC_PPR: u32 = 0x0A0;
-
-/// EOI register. Write-only.
-pub const XAPIC_EOI: u32 = 0x0B0;
-
-/// Logical Destination Register (LDR). Read/write in xAPIC mode.
-pub const XAPIC_LDR: u32 = 0x0D0;
-
-/// Spurious Interrupt Vector Register (SVR). Read/write. See Section 10.9 for reserved bits.
-pub const XAPIC_SVR: u32 = 0x0F0;
-
-/// In-Service Register (ISR); bits 31:0. Read-only.
-pub const XAPIC_ISR0: u32 = 0x100;
-
-/// ISR bits 63:32. Read-only.
-pub const XAPIC_ISR1: u32 = 0x110;
-
-/// ISR bits 95:64. Read-only.
-pub const XAPIC_ISR2: u32 = 0x120;
-
-/// ISR bits 127:96. Read-only.
-pub const XAPIC_ISR3: u32 = 0x130;
-
-/// ISR bits 159:128. Read-only.
-pub const XAPIC_ISR4: u32 = 0x140;
-
-/// ISR bits 191:160. Read-only.
-pub const XAPIC_ISR5: u32 = 0x150;
-
-/// ISR bits 223:192. Read-only.
-pub const XAPIC_ISR6: u32 = 0x160;
-
-/// ISR bits 255:224. Read-only.
-pub const XAPIC_ISR7: u32 = 0x170;
-
-/// Trigger Mode Register (TMR); bits 31:0. Read-only.
-pub const XAPIC_TMR0: u32 = 0x180;
-
-/// TMR bits 63:32. Read-only.
-pub const XAPIC_TMR1: u32 = 0x190;
-
-/// TMR bits 95:64. Read-only.
-pub const XAPIC_TMR2: u32 = 0x1A0;
-
-/// TMR bits 127:96. Read-only.
-pub const XAPIC_TMR3: u32 = 0x1B0;
-
-/// TMR bits 159:128. Read-only.
-pub const XAPIC_TMR4: u32 = 0x1C0;
-
-/// TMR bits 191:160. Read-only.
-pub const XAPIC_TMR5: u32 = 0x1D0;
-
-/// TMR bits 223:192. Read-only.
-pub const XAPIC_TMR6: u32 = 0x1E0;
-
-/// TMR bits 255:224. Read-only.
-pub const XAPIC_TMR7: u32 = 0x1F0;
-
-/// Interrupt Request Register (IRR); bits 31:0. Read-only.
-pub const XAPIC_IRR0: u32 = 0x200;
-
-/// IRR bits 63:32. Read-only.
-pub const XAPIC_IRR1: u32 = 0x210;
-
-/// IRR bits 95:64. Read-only.
-pub const XAPIC_IRR2: u32 = 0x220;
-
-/// IRR bits 127:96. Read-only.
-pub const XAPIC_IRR3: u32 = 0x230;
-
-/// IRR bits 159:128. Read-only.
-pub const XAPIC_IRR4: u32 = 0x240;
-
-/// IRR bits 191:160. Read-only.
-pub const XAPIC_IRR5: u32 = 0x250;
-
-/// IRR bits 223:192. Read-only.
-pub const XAPIC_IRR6: u32 = 0x260;
-
-/// IRR bits 255:224. Read-only.
-pub const XAPIC_IRR7: u32 = 0x270;
-
-/// Error Status Register (ESR). Read/write. See Section 10.5.3.
-pub const XAPIC_ESR: u32 = 0x280;
-
-/// LVT CMCI register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_CMCI: u32 = 0x2F0;
-
-/// Interrupt Command Register (ICR). Read/write. See Figure 10-28 for reserved bits
-pub const XAPIC_ICR0: u32 = 0x300;
-
-/// Interrupt Command Register (ICR). Read/write. See Figure 10-28 for reserved bits
-pub const XAPIC_ICR1: u32 = 0x310;
-
-/// LVT Timer register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_TIMER: u32 = 0x320;
-
-/// LVT Thermal Sensor register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_THERMAL: u32 = 0x330;
-
-/// LVT Performance Monitoring register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_PMI: u32 = 0x340;
-
-/// LVT LINT0 register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_LINT0: u32 = 0x350;
-
-/// LVT LINT1 register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_LINT1: u32 = 0x360;
-
-/// LVT Error register. Read/write. See Figure 10-8 for reserved bits.
-pub const XAPIC_LVT_ERROR: u32 = 0x370;
-
-/// Initial Count register (for Timer). Read/write.
-pub const XAPIC_TIMER_INIT_COUNT: u32 = 0x380;
-
-/// Current Count register (for Timer). Read-only.
-pub const XAPIC_TIMER_CURRENT_COUNT: u32 = 0x390;
-
-/// Divide Configuration Register (DCR; for Timer). Read/write. See Figure 10-10 for reserved bits.
-pub const XAPIC_TIMER_DIV_CONF: u32 = 0x3E0;