diff options
author | 2019-09-12 13:30:08 -0700 | |
---|---|---|
committer | 2019-09-12 13:30:08 -0700 | |
commit | 6ce081418448d69847a4615157d3d8fa89fd188c (patch) | |
tree | 16886cc178cf00c097b7c003ed9dc363df563e19 | |
parent | a9eaf44e421bcdc4e9728ef1b33f90bb538310ec (diff) | |
download | rust-x86-6ce081418448d69847a4615157d3d8fa89fd188c.tar.gz rust-x86-6ce081418448d69847a4615157d3d8fa89fd188c.tar.zst rust-x86-6ce081418448d69847a4615157d3d8fa89fd188c.zip |
Add initial APIC code.
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/apic/ioapic.rs | 101 | ||||
-rw-r--r-- | src/apic/mod.rs | 97 | ||||
-rw-r--r-- | src/apic/x2apic.rs | 86 | ||||
-rw-r--r-- | src/apic/xapic.rs | 356 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/segmentation.rs | 2 | ||||
-rw-r--r-- | src/xapic.rs | 136 |
8 files changed, 645 insertions, 138 deletions
@@ -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; + } + } + } +} @@ -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; |