diff options
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | build.rs | 2 | ||||
-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 |
18 files changed, 90 insertions, 43 deletions
@@ -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 @@ -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 @@ -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. |