aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml9
-rw-r--r--build.rs2
-rw-r--r--src/bitflags.rs1
-rw-r--r--src/controlregs.rs17
-rw-r--r--src/dtables.rs8
-rw-r--r--src/io.rs14
-rw-r--r--src/irq.rs2
-rw-r--r--src/msr.rs6
-rw-r--r--src/paging.rs3
-rw-r--r--src/perfcnt/intel/counters.rs10
-rw-r--r--src/perfcnt/intel/mod.rs2
-rw-r--r--src/perfcnt/mod.rs2
-rw-r--r--src/rflags.rs2
-rw-r--r--src/segmentation.rs14
-rw-r--r--src/syscall.rs2
-rw-r--r--src/task.rs2
-rw-r--r--src/time.rs35
-rw-r--r--src/tlb.rs2
18 files changed, 90 insertions, 43 deletions
diff --git a/Cargo.toml b/Cargo.toml
index c8066f2..11b219b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "x86"
-version = "0.4.0"
+version = "0.5.0"
authors = ["Gerd Zellweger <mail@gerdzellweger.com>", "Eric Kidd <git@randomhacks.net>"]
description = "Library to program x86 (amd64) hardware. Contains x86 specific data structure descriptions, data-tables, as well as convenience function to call assembly instructions typically not exposed in higher level languages."
@@ -14,9 +14,6 @@ keywords = ["ia32", "os", "amd64", "x86", "x86-64"]
license = "MIT"
build = "build.rs"
-[features]
-cached_counters = []
-
[[test]]
name = "no_std_build"
harness = false
@@ -27,8 +24,8 @@ csv = "0.14.3"
serde_json = "0.6.0"
[dependencies]
-raw-cpuid = "1.0.4"
+raw-cpuid = "2.*"
[dependencies.phf]
phf = "0.7.7"
-features = ["core"]
+features = ["core"] \ No newline at end of file
diff --git a/build.rs b/build.rs
index 017fb66..bb80552 100644
--- a/build.rs
+++ b/build.rs
@@ -279,7 +279,7 @@ fn parse_performance_counters(input: &str, variable: &str, file: &mut BufWriter<
}
- write!(file, "const {}: phf::Map<&'static str, IntelPerformanceCounterDescription> = ", variable).unwrap();
+ write!(file, "pub const {}: phf::Map<&'static str, IntelPerformanceCounterDescription> = ", variable).unwrap();
builder.build(file).unwrap();
write!(file, ";\n").unwrap();
}
diff --git a/src/bitflags.rs b/src/bitflags.rs
index a514001..8d16e41 100644
--- a/src/bitflags.rs
+++ b/src/bitflags.rs
@@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[macro_export]
macro_rules! bitflags {
($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
$($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+
diff --git a/src/controlregs.rs b/src/controlregs.rs
index 89242c2..b6cd334 100644
--- a/src/controlregs.rs
+++ b/src/controlregs.rs
@@ -1,44 +1,45 @@
-/// Contains various flags to control operations.
+//! Functions to read and write control registers.
+
pub unsafe fn cr0() -> u64
{
let ret: u64;
- asm!("mov %cr0, $0" : "=r" (ret) : );
+ asm!("mov %cr0, $0" : "=r" (ret));
ret
}
/// Write cr0.
pub unsafe fn cr0_write(val: u64)
{
- asm!("mov $0, %cr0" :: "r" (val));
+ asm!("mov $0, %cr0" :: "r" (val) : "memory");
}
/// Contains page-fault linear address.
pub unsafe fn cr2() -> u64 {
let ret: u64;
- asm!("mov %cr2, $0" : "=r" (ret) :);
+ asm!("mov %cr2, $0" : "=r" (ret));
ret
}
/// Contains page-table root pointer.
pub unsafe fn cr3() -> u64 {
let ret: u64;
- asm!("mov %cr3, $0" : "=r" (ret) :);
+ asm!("mov %cr3, $0" : "=r" (ret));
ret
}
/// Switch page-table PML4 pointer.
pub unsafe fn cr3_write(val: u64) {
- asm!("mov $0, %cr3" :: "r" (val));
+ asm!("mov $0, %cr3" :: "r" (val) : "memory");
}
/// Contains various flags to control operations in protected mode.
pub unsafe fn cr4() -> u64 {
let ret: u64;
- asm!("mov %cr4, $0" : "=r" (ret) :);
+ asm!("mov %cr4, $0" : "=r" (ret));
ret
}
/// Write cr4.
pub unsafe fn cr4_write(val: u64) {
- asm!("mov $0, %cr4" :: "r" (val));
+ asm!("mov $0, %cr4" :: "r" (val) : "memory");
}
diff --git a/src/dtables.rs b/src/dtables.rs
index a47d344..1aff96b 100644
--- a/src/dtables.rs
+++ b/src/dtables.rs
@@ -1,4 +1,4 @@
-/// Functions and data-structures to load descriptor tables.
+//! Functions and data-structures to load descriptor tables.
/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
@@ -13,15 +13,15 @@ pub struct DescriptorTablePointer {
/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
- asm!("lgdt ($0)" :: "r" (gdt));
+ asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}
/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
- asm!("lldt ($0)" :: "r" (ldt));
+ asm!("lldt ($0)" :: "r" (ldt) : "memory");
}
/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
- asm!("lidt ($0)" :: "r" (idt));
+ asm!("lidt ($0)" :: "r" (idt) : "memory");
} \ No newline at end of file
diff --git a/src/io.rs b/src/io.rs
index 0f0e96a..eded102 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -1,35 +1,37 @@
+//! I/O port functionality.
+
/// Write 8 bits to port
pub unsafe fn outb(port: u16, val: u8) {
- asm!("outb %al, %dx" : : "{dx}"(port), "{al}"(val));
+ asm!("outb %al, %dx" :: "{dx}"(port), "{al}"(val));
}
/// Read 8 bits from port
pub unsafe fn inb(port: u16) -> u8 {
let ret : u8;
- asm!("inb %dx, %al" : "={ax}"(ret) : "{dx}"(port));
+ asm!("inb %dx, %al" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
return ret;
}
/// Write 16 bits to port
pub unsafe fn outw(port: u16, val: u16) {
- asm!("outw %ax, %dx" : : "{dx}"(port), "{al}"(val));
+ asm!("outw %ax, %dx" :: "{dx}"(port), "{al}"(val));
}
/// Read 16 bits from port
pub unsafe fn inw(port: u16) -> u16 {
let ret : u16;
- asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(port));
+ asm!("inw %dx, %ax" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
return ret;
}
/// Write 32 bits to port
pub unsafe fn outl(port: u16, val: u32) {
- asm!("outl %eax, %dx" : : "{dx}"(port), "{al}"(val));
+ asm!("outl %eax, %dx" :: "{dx}"(port), "{al}"(val));
}
/// Read 32 bits from port
pub unsafe fn inl(port: u16) -> u32 {
let ret : u32;
- asm!("inl %dx, %eax" : "={ax}"(ret) : "{dx}"(port));
+ asm!("inl %dx, %eax" : "={ax}"(ret) : "{dx}"(port) :: "volatile");
return ret;
}
diff --git a/src/irq.rs b/src/irq.rs
index 50732d2..6aa9beb 100644
--- a/src/irq.rs
+++ b/src/irq.rs
@@ -1,3 +1,5 @@
+//! Interrupt description and set-up code.
+
use core::fmt;
/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
diff --git a/src/msr.rs b/src/msr.rs
index 643e54b..445e6cc 100644
--- a/src/msr.rs
+++ b/src/msr.rs
@@ -1,8 +1,10 @@
+//! MSR value list and function to read and write them.
+
/// Write 64 bits to msr register.
pub unsafe fn wrmsr(msr: u32, value: u64) {
let low = value as u32;
let high = (value >> 32) as u32;
- asm!("wrmsr" :: "{ecx}" (msr), "{eax}" (low), "{edx}" (high) );
+ asm!("wrmsr" :: "{ecx}" (msr), "{eax}" (low), "{edx}" (high) : "memory" : "volatile" );
}
/// Read 64 bits msr register.
@@ -10,7 +12,7 @@ pub unsafe fn wrmsr(msr: u32, value: u64) {
pub unsafe fn rdmsr(msr: u32) -> u64 {
let mut low: u32;
let mut high: u32;
- asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (msr));
+ asm!("rdmsr" : "={eax}" (low), "={edx}" (high) : "{ecx}" (msr) : "memory" : "volatile");
((high as u64) << 32) | (low as u64)
}
diff --git a/src/paging.rs b/src/paging.rs
index f03419f..5c2b5af 100644
--- a/src/paging.rs
+++ b/src/paging.rs
@@ -1,5 +1,4 @@
-/// The focus on this file is to describe the data-structures
-/// for IA-32e paging mode.
+//! Description of the data-structures for IA-32e paging mode.
use core::fmt;
pub type PAddr = u64;
diff --git a/src/perfcnt/intel/counters.rs b/src/perfcnt/intel/counters.rs
index 9d046bf..47495e6 100644
--- a/src/perfcnt/intel/counters.rs
+++ b/src/perfcnt/intel/counters.rs
@@ -1,3 +1,7 @@
+//! Performance counter for all Intel architectures.
+/// The content of this file is automatically generated by `build.rs`
+/// from the data in `x86data/perfmon_data`.
+
use phf;
use super::description::IntelPerformanceCounterDescription;
use super::description::Counter;
@@ -5,8 +9,4 @@ use super::description::PebsType;
use super::description::Tuple;
use super::description::MSRIndex;
-#[cfg(not(feature = "cached_counters"))]
-include!(concat!(env!("OUT_DIR"), "/counters.rs"));
-
-#[cfg(feature = "cached_counters")]
-include!("generated.rs");
+include!(concat!(env!("OUT_DIR"), "/counters.rs")); \ No newline at end of file
diff --git a/src/perfcnt/intel/mod.rs b/src/perfcnt/intel/mod.rs
index 25b22dc..99793be 100644
--- a/src/perfcnt/intel/mod.rs
+++ b/src/perfcnt/intel/mod.rs
@@ -1,2 +1,4 @@
+//! Information about Intel's performance counters.
+
pub mod counters;
pub mod description; \ No newline at end of file
diff --git a/src/perfcnt/mod.rs b/src/perfcnt/mod.rs
index 00fabe3..431f00e 100644
--- a/src/perfcnt/mod.rs
+++ b/src/perfcnt/mod.rs
@@ -1,3 +1,5 @@
+//! Information about available performance counters.
+
use super::cpuid;
use phf;
diff --git a/src/rflags.rs b/src/rflags.rs
index c45c1ca..2fadd51 100644
--- a/src/rflags.rs
+++ b/src/rflags.rs
@@ -1,3 +1,5 @@
+//! Description of RFlag values that store the results of operations and the state of the processor.
+
/// RFLAGS description.
bitflags! {
flags RFlags: u64 {
diff --git a/src/segmentation.rs b/src/segmentation.rs
index e00ea34..d2354d4 100644
--- a/src/segmentation.rs
+++ b/src/segmentation.rs
@@ -1,3 +1,5 @@
+//! Program x86 segmentation hardware.
+
use core::fmt;
/// Specifies which element to load into a segment from
@@ -161,27 +163,27 @@ impl fmt::Debug for SegmentDescriptor {
/// Reload stack segment register.
pub unsafe fn load_ss(sel: SegmentSelector) {
- asm!("movw $0, %ss " :: "r" (sel));
+ asm!("movw $0, %ss " :: "r" (sel) : "memory");
}
/// Reload data segment register.
pub unsafe fn load_ds(sel: SegmentSelector) {
- asm!("movw $0, %ds " :: "r" (sel));
+ asm!("movw $0, %ds " :: "r" (sel) : "memory");
}
/// Reload fs segment register.
pub unsafe fn load_es(sel: SegmentSelector) {
- asm!("movw $0, %es " :: "r" (sel));
+ asm!("movw $0, %es " :: "r" (sel) : "memory");
}
/// Reload fs segment register.
pub unsafe fn load_fs(sel: SegmentSelector) {
- asm!("movw $0, %fs " :: "r" (sel));
+ asm!("movw $0, %fs " :: "r" (sel) : "memory");
}
/// Reload gs segment register.
pub unsafe fn load_gs(sel: SegmentSelector) {
- asm!("movw $0, %gs " :: "r" (sel));
+ asm!("movw $0, %gs " :: "r" (sel) : "memory");
}
/// Reload code segment register.
@@ -194,5 +196,5 @@ pub unsafe fn load_cs(sel: SegmentSelector) {
lea 1f(%rip), %rax
pushq %rax
lretq
- 1:" :: "r" (sel.bits() as u64) : "{rax}");
+ 1:" :: "r" (sel.bits() as u64) : "{rax}" "memory");
}
diff --git a/src/syscall.rs b/src/syscall.rs
index 681f73f..01d87fd 100644
--- a/src/syscall.rs
+++ b/src/syscall.rs
@@ -1,4 +1,4 @@
-/// SYSCALL invokes an OS system-call handler at privilege level 0.
+//! Invokes an OS system-call handler at privilege level 0.
///
/// It does so by loading RIP from the IA32_LSTAR MSR (after saving the address of the instruction following SYSCALL into RCX).
///
diff --git a/src/task.rs b/src/task.rs
index 8360b71..c4e37bf 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -1,3 +1,5 @@
+//! Helpers to program the task state segment.
+
use segmentation;
pub type TaskStateDescriptorLow = segmentation::SegmentDescriptor;
diff --git a/src/time.rs b/src/time.rs
index ad8f466..7d402f4 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -1,5 +1,18 @@
+//! Functions to read time stamp counters on x86.
/// Read the time stamp counter.
+///
+/// The RDTSC instruction is not a serializing instruction.
+/// It does not necessarily wait until all previous instructions
+/// have been executed before reading the counter. Similarly,
+/// subsequent instructions may begin execution before the
+/// read operation is performed. If software requires RDTSC to be
+/// executed only after all previous instructions have completed locally,
+/// it can either use RDTSCP or execute the sequence LFENCE;RDTSC.
+///
+/// # Safety
+/// * Causes a GP fault if the TSD flag in register CR4 is set and the CPL
+/// is greater than 0.
#[allow(unused_mut)]
pub unsafe fn rdtsc() -> u64 {
let mut low: u32;
@@ -8,3 +21,25 @@ pub unsafe fn rdtsc() -> u64 {
asm!("rdtsc" : "={eax}" (low), "={edx}" (high));
((high as u64) << 32) | (low as u64)
}
+
+/// Read the time stamp counter.
+///
+/// The RDTSCP instruction waits until all previous instructions
+/// have been executed before reading the counter.
+/// However, subsequent instructions may begin execution
+/// before the read operation is performed.
+///
+/// Volatile is used here because the function may be used to act as
+/// an instruction barrier.
+///
+/// # Safety
+/// * Causes a GP fault if the TSD flag in register CR4 is set and the
+/// CPL is greater than 0.
+#[allow(unused_mut)]
+pub unsafe fn rdtscp() -> u64 {
+ let mut low: u32;
+ let mut high: u32;
+
+ asm!("rdtscp" : "={eax}" (low), "={edx}" (high) ::: "volatile");
+ ((high as u64) << 32) | (low as u64)
+} \ No newline at end of file
diff --git a/src/tlb.rs b/src/tlb.rs
index f20e37e..ec39e3e 100644
--- a/src/tlb.rs
+++ b/src/tlb.rs
@@ -6,7 +6,7 @@
/// This function is unsafe as it causes a general protection fault (GP) if the current privilege
/// level is not 0.
pub unsafe fn flush(addr: usize) {
- asm!("invlpg ($0)" :: "r" (addr) : "memory" : "volatile");
+ asm!("invlpg ($0)" :: "r" (addr) : "memory");
}
/// Invalidate the TLB completely by reloading the CR3 register.