aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2015-11-29 12:17:36 +0100
committerGravatar Gerd Zellweger <mail@gerdzellweger.com> 2015-11-29 12:17:36 +0100
commit8ea2eb2dc442e9d0e89e08d40283b1aaba1cc87a (patch)
treeeaa63e77f9386864c26fb87a9f50f4628611abc8 /src
parentbec7731473a0fae1d837a8a0fdfc902504ea9fcd (diff)
downloadrust-x86-8ea2eb2dc442e9d0e89e08d40283b1aaba1cc87a.tar.gz
rust-x86-8ea2eb2dc442e9d0e89e08d40283b1aaba1cc87a.tar.zst
rust-x86-8ea2eb2dc442e9d0e89e08d40283b1aaba1cc87a.zip
Fixing volatile and memory attributes for assembly.
For volatile: You can prevent an asm instruction from being deleted by writing the keyword volatile after the asm. [...] The volatile keyword indicates that the instruction has important side-effects. GCC will not delete a volatile asm if it is reachable. and An asm instruction without any output operands will be treated identically to a volatile asm instruction. And for memory: This will cause GCC to not keep memory values cached in registers across the assembler instruction and not optimize stores or loads to that memory. See also: https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Extended-Asm.html http://stackoverflow.com/questions/14449141/the-difference-between-asm-asm-volatile-and-clobbering-memory
Diffstat (limited to 'src')
-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
16 files changed, 86 insertions, 36 deletions
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.