Skip to content

Commit 2792ba6

Browse files
authored
Merge pull request #251 from rust-osdev/asm
Multiple improvements to the inline assembly code
2 parents 73f17a2 + 2d1e4a2 commit 2792ba6

15 files changed

+225
-244
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ inline_asm = []
4242
abi_x86_interrupt = []
4343
const_fn = []
4444

45+
[package.metadata.docs.rs]
46+
rustdoc-args = ["--cfg", "docsrs"]
47+
4548
[package.metadata.release]
4649
no-dev-version = true
4750
pre-release-replacements = [

Changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Unreleased
22

3+
- Multiple improvements to assembly code ([#251](https://github.com/rust-osdev/x86_64/pull/251))
4+
- Added `external_asm` implementations for `bochs_breakpoint` and `XCr0`
5+
- Updated `options` for `asm!` blocks (to improve performance)
6+
- Updated docs to use [`doc_cfg`](https://doc.rust-lang.org/unstable-book/language-features/doc-cfg.html)
7+
38
# 0.14.1 – 2021-05-06
49

510
- Use new `const_fn_trait_bound` feature to fix build on latest nightly ([#250](https://github.com/rust-osdev/x86_64/pull/250))

src/asm/asm.s

+35-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
.text
22
.code64
33

4+
# REMEMBER: This code uses the AMD64 calling convention:
5+
# Arguments: RDI, RSI, RDX, RCX
6+
# Return: RAX
7+
48
.global _x86_64_asm_interrupt_enable
59
.p2align 4
610
_x86_64_asm_interrupt_enable:
@@ -135,11 +139,8 @@ _x86_64_asm_write_rflags:
135139
.global _x86_64_asm_read_rflags
136140
.p2align 4
137141
_x86_64_asm_read_rflags:
138-
pushq %rbp
139-
movq %rsp, %rbp
140142
pushfq
141143
popq %rax
142-
popq %rbp
143144
retq
144145

145146
.global _x86_64_asm_load_ss
@@ -223,21 +224,19 @@ _x86_64_asm_write_cr4:
223224
.global _x86_64_asm_rdmsr
224225
.p2align 4
225226
_x86_64_asm_rdmsr:
226-
mov %edi,%ecx
227+
mov %edi, %ecx # First param is the MSR number
227228
rdmsr
228-
shl $0x20,%rdx # shift edx to upper 32bit
229-
mov %eax,%eax # clear upper 32bit of rax
230-
or %rdx,%rax # or with rdx
229+
shl $32, %rdx # shift edx to upper 32bit
230+
mov %eax, %eax # clear upper 32bit of rax
231+
or %rdx, %rax # or with rdx
231232
retq
232233

233234
.global _x86_64_asm_wrmsr
234235
.p2align 4
235236
_x86_64_asm_wrmsr:
236-
mov %edi,%ecx
237-
movq %rsi,%rax
238-
movq %rsi,%rdx
239-
shr $0x20,%rdx
240-
wrmsr
237+
movl %edi, %ecx # First param is the MSR number
238+
movl %esi, %eax # Second param is the low 32-bits
239+
wrmsr # Third param (high 32-bits) is already in %edx
241240
retq
242241

243242
.global _x86_64_asm_hlt
@@ -252,6 +251,12 @@ _x86_64_asm_nop:
252251
nop
253252
retq
254253

254+
.global _x86_64_asm_bochs
255+
.p2align 4
256+
_x86_64_asm_bochs:
257+
xchgw %bx, %bx
258+
retq
259+
255260
.global _x86_64_asm_rdfsbase
256261
.p2align 4
257262
_x86_64_asm_rdfsbase:
@@ -275,3 +280,21 @@ _x86_64_asm_rdgsbase:
275280
_x86_64_asm_wrgsbase:
276281
wrgsbase %rdi
277282
retq
283+
284+
.global _x86_64_asm_xgetbv
285+
.p2align 4
286+
_x86_64_asm_xgetbv:
287+
mov %edi, %ecx # First param is the XCR number
288+
xgetbv
289+
shl $32, %rdx # shift edx to upper 32bit
290+
mov %eax, %eax # clear upper 32bit of rax
291+
or %rdx, %rax # or with rdx
292+
retq
293+
294+
.global _x86_64_asm_xsetbv
295+
.p2align 4
296+
_x86_64_asm_xsetbv:
297+
movl %edi, %ecx # First param is the XCR number
298+
movl %esi, %eax # Second param is the low 32-bits
299+
xsetbv # Third param (high 32-bits) is already in %edx
300+
retq

src/asm/mod.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ extern "C" {
3636
)]
3737
pub(crate) fn x86_64_asm_nop();
3838

39+
#[cfg_attr(
40+
any(target_env = "gnu", target_env = "musl"),
41+
link_name = "_x86_64_asm_bochs"
42+
)]
43+
pub(crate) fn x86_64_asm_bochs();
44+
3945
#[cfg_attr(
4046
any(target_env = "gnu", target_env = "musl"),
4147
link_name = "_x86_64_asm_read_from_port_u8"
@@ -208,7 +214,7 @@ extern "C" {
208214
any(target_env = "gnu", target_env = "musl"),
209215
link_name = "_x86_64_asm_wrmsr"
210216
)]
211-
pub(crate) fn x86_64_asm_wrmsr(msr: u32, value: u64);
217+
pub(crate) fn x86_64_asm_wrmsr(msr: u32, low: u32, high: u32);
212218

213219
#[cfg_attr(
214220
any(target_env = "gnu", target_env = "musl"),
@@ -245,4 +251,16 @@ extern "C" {
245251
link_name = "_x86_64_asm_wrgsbase"
246252
)]
247253
pub(crate) fn x86_64_asm_wrgsbase(val: u64);
254+
255+
#[cfg_attr(
256+
any(target_env = "gnu", target_env = "musl"),
257+
link_name = "_x86_64_asm_xgetbv"
258+
)]
259+
pub(crate) fn x86_64_asm_xgetbv(xcr: u32) -> u64;
260+
261+
#[cfg_attr(
262+
any(target_env = "gnu", target_env = "musl"),
263+
link_name = "_x86_64_asm_xsetbv"
264+
)]
265+
pub(crate) fn x86_64_asm_xsetbv(xcr: u32, low: u32, high: u32);
248266
}

src/instructions/interrupts.rs

+11-25
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ pub fn are_enabled() -> bool {
1313
/// This is a wrapper around the `sti` instruction.
1414
#[inline]
1515
pub fn enable() {
16-
#[cfg(feature = "inline_asm")]
1716
unsafe {
17+
#[cfg(feature = "inline_asm")]
1818
asm!("sti", options(nomem, nostack));
19-
}
20-
#[cfg(not(feature = "inline_asm"))]
21-
unsafe {
19+
20+
#[cfg(not(feature = "inline_asm"))]
2221
crate::asm::x86_64_asm_interrupt_enable();
2322
}
2423
}
@@ -28,13 +27,11 @@ pub fn enable() {
2827
/// This is a wrapper around the `cli` instruction.
2928
#[inline]
3029
pub fn disable() {
31-
#[cfg(feature = "inline_asm")]
3230
unsafe {
31+
#[cfg(feature = "inline_asm")]
3332
asm!("cli", options(nomem, nostack));
34-
}
3533

36-
#[cfg(not(feature = "inline_asm"))]
37-
unsafe {
34+
#[cfg(not(feature = "inline_asm"))]
3835
crate::asm::x86_64_asm_interrupt_disable();
3936
}
4037
}
@@ -129,26 +126,23 @@ where
129126
/// information.
130127
#[inline]
131128
pub fn enable_and_hlt() {
132-
#[cfg(feature = "inline_asm")]
133129
unsafe {
130+
#[cfg(feature = "inline_asm")]
134131
asm!("sti; hlt", options(nomem, nostack));
135-
}
136-
#[cfg(not(feature = "inline_asm"))]
137-
unsafe {
132+
133+
#[cfg(not(feature = "inline_asm"))]
138134
crate::asm::x86_64_asm_interrupt_enable_and_hlt();
139135
}
140136
}
141137

142138
/// Cause a breakpoint exception by invoking the `int3` instruction.
143139
#[inline]
144140
pub fn int3() {
145-
#[cfg(feature = "inline_asm")]
146141
unsafe {
142+
#[cfg(feature = "inline_asm")]
147143
asm!("int3", options(nomem, nostack));
148-
}
149144

150-
#[cfg(not(feature = "inline_asm"))]
151-
unsafe {
145+
#[cfg(not(feature = "inline_asm"))]
152146
crate::asm::x86_64_asm_int3();
153147
}
154148
}
@@ -159,18 +153,10 @@ pub fn int3() {
159153
/// immediate. This macro will be replaced by a generic function when support for
160154
/// const generics is implemented in Rust.
161155
#[cfg(feature = "inline_asm")]
156+
#[cfg_attr(docsrs, doc(cfg(any(feature = "nightly", feature = "inline_asm"))))]
162157
#[macro_export]
163158
macro_rules! software_interrupt {
164159
($x:expr) => {{
165160
asm!("int {id}", id = const $x, options(nomem, nostack));
166161
}};
167162
}
168-
169-
/// Not implemented
170-
#[cfg(not(feature = "inline_asm"))]
171-
#[macro_export]
172-
macro_rules! software_interrupt {
173-
($x:expr) => {{
174-
compile_error!("software_interrupt not implemented for non-nightly");
175-
}};
176-
}

src/instructions/mod.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ pub mod tlb;
1212
/// Halts the CPU until the next interrupt arrives.
1313
#[inline]
1414
pub fn hlt() {
15-
#[cfg(feature = "inline_asm")]
1615
unsafe {
17-
asm!("hlt", options(nomem, nostack));
18-
}
16+
#[cfg(feature = "inline_asm")]
17+
asm!("hlt", options(nomem, nostack, preserves_flags));
1918

20-
#[cfg(not(feature = "inline_asm"))]
21-
unsafe {
19+
#[cfg(not(feature = "inline_asm"))]
2220
crate::asm::x86_64_asm_hlt();
2321
}
2422
}
@@ -31,37 +29,37 @@ pub fn hlt() {
3129
/// endless loop away.
3230
#[inline]
3331
pub fn nop() {
34-
#[cfg(feature = "inline_asm")]
3532
unsafe {
33+
#[cfg(feature = "inline_asm")]
3634
asm!("nop", options(nomem, nostack, preserves_flags));
37-
}
3835

39-
#[cfg(not(feature = "inline_asm"))]
40-
unsafe {
36+
#[cfg(not(feature = "inline_asm"))]
4137
crate::asm::x86_64_asm_nop();
4238
}
4339
}
4440

4541
/// Emits a '[magic breakpoint](https://wiki.osdev.org/Bochs#Magic_Breakpoint)' instruction for the [Bochs](http://bochs.sourceforge.net/) CPU
4642
/// emulator. Make sure to set `magic_break: enabled=1` in your `.bochsrc` file.
47-
#[cfg(feature = "inline_asm")]
4843
#[inline]
4944
pub fn bochs_breakpoint() {
5045
unsafe {
51-
asm!("xchg bx, bx", options(nomem, nostack));
46+
#[cfg(feature = "inline_asm")]
47+
asm!("xchg bx, bx", options(nomem, nostack, preserves_flags));
48+
49+
#[cfg(not(feature = "inline_asm"))]
50+
crate::asm::x86_64_asm_bochs();
5251
}
5352
}
5453

5554
/// Gets the current instruction pointer. Note that this is only approximate as it requires a few
5655
/// instructions to execute.
5756
#[cfg(feature = "inline_asm")]
57+
#[cfg_attr(docsrs, doc(cfg(any(feature = "nightly", feature = "inline_asm"))))]
5858
#[inline(always)]
5959
pub fn read_rip() -> crate::VirtAddr {
6060
let rip: u64;
6161
unsafe {
62-
asm!(
63-
"lea {}, [rip]", out(reg) rip, options(nostack, nomem)
64-
);
62+
asm!("lea {}, [rip]", out(reg) rip, options(nostack, nomem, preserves_flags));
6563
}
6664
crate::VirtAddr::new(rip)
6765
}

0 commit comments

Comments
 (0)