Skip to content

Commit 52fc1d0

Browse files
committed
Decouple instructions into a separate feature flag.
1 parent 3ce339e commit 52fc1d0

File tree

16 files changed

+196
-177
lines changed

16 files changed

+196
-177
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ array-init = { version = "0.1.1", optional = true }
3434
cc = { version = "1.0.37", optional = true }
3535

3636
[features]
37-
default = [ "nightly" ]
37+
default = [ "nightly", "instructions" ]
38+
instructions = []
3839
deny-warnings = []
39-
stable = [ "cc", "array-init" ]
40+
external_asm = [ "cc", "array-init" ]
4041
nightly = [ "inline_asm", "const_fn", "abi_x86_interrupt" ]
4142
inline_asm = []
4243
abi_x86_interrupt = []

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Support for x86_64 specific instructions (e.g. TLB flush), registers (e.g. contr
88
## Crate Feature Flags
99

1010
* `nightly`: This is the default.
11-
* `stable`: Use this to build with non-nightly rust. Needs `default-features = false`.
11+
* `instructions`: Enabled by default, turns on x86\_64 specific instructions, and dependent features. Only available for x86\_64 targets.
12+
* `external_asm`: Use this to build with non-nightly rust. Needs `default-features = false, features = ["instructions"]`. Is unsupported on Windows.
1213

1314
## Building with stable rust
1415

build.rs

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,52 @@
1-
#[cfg(feature = "inline_asm")]
2-
fn main() {}
3-
4-
#[cfg(all(not(feature = "inline_asm"), not(feature = "stable")))]
51
fn main() {
6-
compile_error!("Neither feature \"stable\" nor \"nightly\" was set!");
7-
}
2+
println!("cargo:rerun-if-changed=build.rs");
83

9-
#[cfg(all(not(feature = "inline_asm"), feature = "stable"))]
10-
fn main() {
11-
use std::ffi::OsString;
12-
use std::fs;
4+
#[cfg(all(feature = "external_asm", windows))]
5+
compile_error!("\"external_asm\" feature is not available on windows!");
136

14-
println!("cargo:rerun-if-changed=build.rs");
7+
#[cfg(all(feature = "instructions", not(target_arch = "x86_64")))]
8+
compile_error!("\"instructions\" feature is only available for x86_64 targets!");
159

16-
let entries = fs::read_dir("src/asm")
17-
.unwrap()
18-
.filter_map(|f| {
19-
f.ok().and_then(|e| {
20-
let path = e.path();
21-
match path.extension() {
22-
Some(ext) if ext.eq(&OsString::from("s")) => Some(path),
23-
_ => None,
24-
}
10+
#[cfg(all(
11+
feature = "instructions",
12+
not(feature = "inline_asm"),
13+
not(feature = "external_asm")
14+
))]
15+
compile_error!("\"instructions\" feature is enabled, but neither feature \"external_asm\" nor \"inline_asm\" was set!");
16+
17+
#[cfg(all(feature = "inline_asm", feature = "external_asm"))]
18+
compile_error!(
19+
"\"inline_asm\" and \"external_asm\" features can not be enabled at the same time!"
20+
);
21+
22+
#[cfg(all(feature = "instructions", feature = "external_asm"))]
23+
{
24+
use std::ffi::OsString;
25+
use std::fs;
26+
27+
let entries = fs::read_dir("src/asm")
28+
.unwrap()
29+
.filter_map(|f| {
30+
f.ok().and_then(|e| {
31+
let path = e.path();
32+
match path.extension() {
33+
Some(ext) if ext.eq(&OsString::from("s")) => Some(path),
34+
_ => None,
35+
}
36+
})
2537
})
26-
})
27-
.collect::<Vec<_>>();
28-
29-
cc::Build::new()
30-
.no_default_flags(true)
31-
.files(&entries)
32-
.pic(true)
33-
.static_flag(true)
34-
.shared_flag(false)
35-
.compile("x86_64_asm");
36-
37-
for e in entries {
38-
println!("cargo:rerun-if-changed={}", e.to_str().unwrap());
38+
.collect::<Vec<_>>();
39+
40+
cc::Build::new()
41+
.no_default_flags(true)
42+
.files(&entries)
43+
.pic(true)
44+
.static_flag(true)
45+
.shared_flag(false)
46+
.compile("x86_64_asm");
47+
48+
for e in entries {
49+
println!("cargo:rerun-if-changed={}", e.to_str().unwrap());
50+
}
3951
}
4052
}

src/instructions/mod.rs

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![cfg(target_arch = "x86_64")]
1+
#![cfg(feature = "instructions")]
22

33
//! Special x86_64 instructions.
44
@@ -51,3 +51,117 @@ pub fn bochs_breakpoint() {
5151
llvm_asm!("xchgw %bx, %bx" :::: "volatile");
5252
}
5353
}
54+
55+
/// Gets the current instruction pointer. Note that this is only approximate as it requires a few
56+
/// instructions to execute.
57+
#[cfg(feature = "inline_asm")]
58+
#[inline(always)]
59+
pub fn read_rip() -> u64 {
60+
let rip: u64;
61+
unsafe {
62+
llvm_asm!(
63+
"lea (%rip), $0"
64+
: "=r"(rip) ::: "volatile"
65+
);
66+
}
67+
rip
68+
}
69+
70+
/// Writes the FS segment base address
71+
///
72+
/// ## Safety
73+
///
74+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
75+
///
76+
/// The caller must ensure that this write operation has no unsafe side
77+
/// effects, as the FS segment base address is often used for thread
78+
/// local storage.
79+
#[inline]
80+
pub unsafe fn wrfsbase(val: u64) {
81+
#[cfg(feature = "inline_asm")]
82+
#[inline(always)]
83+
unsafe fn inner(val: u64) {
84+
llvm_asm!("wrfsbase $0" :: "r"(val) :: "volatile")
85+
}
86+
87+
#[cfg(not(feature = "inline_asm"))]
88+
#[inline(always)]
89+
unsafe fn inner(val: u64) {
90+
crate::asm::x86_64_asm_wrfsbase(val)
91+
}
92+
93+
inner(val)
94+
}
95+
96+
/// Reads the FS segment base address
97+
///
98+
/// ## Safety
99+
///
100+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
101+
#[inline]
102+
pub unsafe fn rdfsbase() -> u64 {
103+
#[cfg(feature = "inline_asm")]
104+
#[inline(always)]
105+
unsafe fn inner() -> u64 {
106+
let val: u64;
107+
llvm_asm!("rdfsbase $0" : "=r" (val) ::: "volatile");
108+
val
109+
}
110+
111+
#[cfg(not(feature = "inline_asm"))]
112+
#[inline(always)]
113+
unsafe fn inner() -> u64 {
114+
crate::asm::x86_64_asm_rdfsbase()
115+
}
116+
117+
inner()
118+
}
119+
120+
/// Writes the GS segment base address
121+
///
122+
/// ## Safety
123+
///
124+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
125+
///
126+
/// The caller must ensure that this write operation has no unsafe side
127+
/// effects, as the GS segment base address might be in use.
128+
#[inline]
129+
pub unsafe fn wrgsbase(val: u64) {
130+
#[cfg(feature = "inline_asm")]
131+
#[inline(always)]
132+
unsafe fn inner(val: u64) {
133+
llvm_asm!("wrgsbase $0" :: "r"(val) :: "volatile")
134+
}
135+
136+
#[cfg(not(feature = "inline_asm"))]
137+
#[inline(always)]
138+
unsafe fn inner(val: u64) {
139+
crate::asm::x86_64_asm_wrgsbase(val)
140+
}
141+
142+
inner(val)
143+
}
144+
145+
/// Reads the GS segment base address
146+
///
147+
/// ## Safety
148+
///
149+
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
150+
#[inline]
151+
pub unsafe fn rdgsbase() -> u64 {
152+
#[cfg(feature = "inline_asm")]
153+
#[inline(always)]
154+
unsafe fn inner() -> u64 {
155+
let val: u64;
156+
llvm_asm!("rdgsbase $0" : "=r" (val) ::: "volatile");
157+
val
158+
}
159+
160+
#[cfg(not(feature = "inline_asm"))]
161+
#[inline(always)]
162+
unsafe fn inner() -> u64 {
163+
crate::asm::x86_64_asm_rdgsbase()
164+
}
165+
166+
inner()
167+
}

src/instructions/random.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
/// Used to obtain random numbers using x86_64's RDRAND opcode
55
pub struct RdRand(());
66

7-
#[cfg(target_arch = "x86_64")]
87
impl RdRand {
98
/// Creates Some(RdRand) if RDRAND is supported, None otherwise
109
#[inline]
@@ -66,7 +65,7 @@ impl RdRand {
6665
}
6766
}
6867

69-
#[cfg(all(test, target_arch = "x86_64"))]
68+
#[cfg(all(test))]
7069
mod tests {
7170
use super::*;
7271

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ macro_rules! const_fn {
3232
}
3333
}
3434

35-
#[cfg(not(feature = "inline_asm"))]
35+
#[cfg(all(feature = "instructions", not(feature = "inline_asm")))]
3636
pub(crate) mod asm;
3737

3838
pub mod addr;

src/registers/control.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ bitflags! {
125125
}
126126
}
127127

128-
#[cfg(target_arch = "x86_64")]
128+
#[cfg(feature = "instructions")]
129129
mod x86_64 {
130130
use super::*;
131131
use crate::structures::paging::PhysFrame;

src/registers/mod.rs

Lines changed: 4 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -4,116 +4,8 @@ pub mod control;
44
pub mod model_specific;
55
pub mod rflags;
66

7-
/// Gets the current instruction pointer. Note that this is only approximate as it requires a few
8-
/// instructions to execute.
9-
#[cfg(feature = "inline_asm")]
10-
#[inline(always)]
11-
pub fn read_rip() -> u64 {
12-
let rip: u64;
13-
unsafe {
14-
llvm_asm!(
15-
"lea (%rip), $0"
16-
: "=r"(rip) ::: "volatile"
17-
);
18-
}
19-
rip
20-
}
7+
#[cfg(feature = "instructions")]
8+
pub use crate::instructions::{rdfsbase, rdgsbase, wrfsbase, wrgsbase};
219

22-
/// Writes the FS segment base address
23-
///
24-
/// ## Safety
25-
///
26-
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
27-
///
28-
/// The caller must ensure that this write operation has no unsafe side
29-
/// effects, as the FS segment base address is often used for thread
30-
/// local storage.
31-
#[inline]
32-
pub unsafe fn wrfsbase(val: u64) {
33-
#[cfg(feature = "inline_asm")]
34-
#[inline(always)]
35-
unsafe fn inner(val: u64) {
36-
llvm_asm!("wrfsbase $0" :: "r"(val) :: "volatile")
37-
}
38-
39-
#[cfg(not(feature = "inline_asm"))]
40-
#[inline(always)]
41-
unsafe fn inner(val: u64) {
42-
crate::asm::x86_64_asm_wrfsbase(val)
43-
}
44-
45-
inner(val)
46-
}
47-
48-
/// Reads the FS segment base address
49-
///
50-
/// ## Safety
51-
///
52-
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
53-
#[inline]
54-
pub unsafe fn rdfsbase() -> u64 {
55-
#[cfg(feature = "inline_asm")]
56-
#[inline(always)]
57-
unsafe fn inner() -> u64 {
58-
let val: u64;
59-
llvm_asm!("rdfsbase $0" : "=r" (val) ::: "volatile");
60-
val
61-
}
62-
63-
#[cfg(not(feature = "inline_asm"))]
64-
#[inline(always)]
65-
unsafe fn inner() -> u64 {
66-
crate::asm::x86_64_asm_rdfsbase()
67-
}
68-
69-
inner()
70-
}
71-
72-
/// Writes the GS segment base address
73-
///
74-
/// ## Safety
75-
///
76-
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
77-
///
78-
/// The caller must ensure that this write operation has no unsafe side
79-
/// effects, as the GS segment base address might be in use.
80-
#[inline]
81-
pub unsafe fn wrgsbase(val: u64) {
82-
#[cfg(feature = "inline_asm")]
83-
#[inline(always)]
84-
unsafe fn inner(val: u64) {
85-
llvm_asm!("wrgsbase $0" :: "r"(val) :: "volatile")
86-
}
87-
88-
#[cfg(not(feature = "inline_asm"))]
89-
#[inline(always)]
90-
unsafe fn inner(val: u64) {
91-
crate::asm::x86_64_asm_wrgsbase(val)
92-
}
93-
94-
inner(val)
95-
}
96-
97-
/// Reads the GS segment base address
98-
///
99-
/// ## Safety
100-
///
101-
/// If `CR4.FSGSBASE` is not set, this instruction will throw an `#UD`.
102-
#[inline]
103-
pub unsafe fn rdgsbase() -> u64 {
104-
#[cfg(feature = "inline_asm")]
105-
#[inline(always)]
106-
unsafe fn inner() -> u64 {
107-
let val: u64;
108-
llvm_asm!("rdgsbase $0" : "=r" (val) ::: "volatile");
109-
val
110-
}
111-
112-
#[cfg(not(feature = "inline_asm"))]
113-
#[inline(always)]
114-
unsafe fn inner() -> u64 {
115-
crate::asm::x86_64_asm_rdgsbase()
116-
}
117-
118-
inner()
119-
}
10+
#[cfg(all(feature = "instructions", feature = "inline_asm"))]
11+
pub use crate::instructions::read_rip;

0 commit comments

Comments
 (0)