diff options
author | 2015-11-29 12:17:36 +0100 | |
---|---|---|
committer | 2015-11-29 12:17:36 +0100 | |
commit | 8ea2eb2dc442e9d0e89e08d40283b1aaba1cc87a (patch) | |
tree | eaa63e77f9386864c26fb87a9f50f4628611abc8 /src | |
parent | bec7731473a0fae1d837a8a0fdfc902504ea9fcd (diff) | |
download | rust-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.rs | 1 | ||||
-rw-r--r-- | src/controlregs.rs | 17 | ||||
-rw-r--r-- | src/dtables.rs | 8 | ||||
-rw-r--r-- | src/io.rs | 14 | ||||
-rw-r--r-- | src/irq.rs | 2 | ||||
-rw-r--r-- | src/msr.rs | 6 | ||||
-rw-r--r-- | src/paging.rs | 3 | ||||
-rw-r--r-- | src/perfcnt/intel/counters.rs | 10 | ||||
-rw-r--r-- | src/perfcnt/intel/mod.rs | 2 | ||||
-rw-r--r-- | src/perfcnt/mod.rs | 2 | ||||
-rw-r--r-- | src/rflags.rs | 2 | ||||
-rw-r--r-- | src/segmentation.rs | 14 | ||||
-rw-r--r-- | src/syscall.rs | 2 | ||||
-rw-r--r-- | src/task.rs | 2 | ||||
-rw-r--r-- | src/time.rs | 35 | ||||
-rw-r--r-- | src/tlb.rs | 2 |
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 @@ -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; } @@ -1,3 +1,5 @@ +//! Interrupt description and set-up code. + use core::fmt; /// x86 Exception description (see also Intel Vol. 3a Chapter 6). @@ -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 @@ -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. |