From 204e6e33c89b197c94b25a34ba42b2b9f2f333c0 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 3 Feb 2022 13:52:12 +0100 Subject: [PATCH 01/27] Update changelog for #334 and #336 --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 8f57b26b2..4b26f90fa 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ # Unreleased +- Add `Cr2::read_raw` ([#334](https://github.com/rust-osdev/x86_64/pull/334)) +- Add support for `MXCSR` register ([#336](https://github.com/rust-osdev/x86_64/pull/336)) + # 0.14.7 – 2021-12-18 - fix: build error on the latest nightly ([#329](https://github.com/rust-osdev/x86_64/pull/329)) From 5c4f5ee63115ed46dfef6ec97215d03163ed1eb3 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 3 Feb 2022 13:53:23 +0100 Subject: [PATCH 02/27] Bump version to 0.14.8 --- Cargo.toml | 2 +- Changelog.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ea643c922..ffec90e41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ license = "MIT/Apache-2.0" name = "x86_64" readme = "README.md" repository = "https://github.com/rust-osdev/x86_64" -version = "0.14.7" +version = "0.14.8" edition = "2018" [dependencies] diff --git a/Changelog.md b/Changelog.md index 4b26f90fa..a64977e74 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,7 @@ # Unreleased +# 0.14.8 – 2022-02-03 + - Add `Cr2::read_raw` ([#334](https://github.com/rust-osdev/x86_64/pull/334)) - Add support for `MXCSR` register ([#336](https://github.com/rust-osdev/x86_64/pull/336)) From 760fa3d0b61e013d25281bf8db5ea17e5b8072b7 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 5 Feb 2022 12:09:35 +0100 Subject: [PATCH 03/27] make fields public --- src/addr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index b71d7b63d..74f677453 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -41,7 +41,7 @@ pub struct PhysAddr(u64); /// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid /// address calculation. #[derive(Debug)] -pub struct VirtAddrNotValid(u64); +pub struct VirtAddrNotValid(pub u64); impl VirtAddr { /// Creates a new canonical virtual address. @@ -326,7 +326,7 @@ impl Sub for VirtAddr { /// /// This means that bits 52 to 64 were not all null. #[derive(Debug)] -pub struct PhysAddrNotValid(u64); +pub struct PhysAddrNotValid(pub u64); impl PhysAddr { /// Creates a new physical address. From a143355627240bd58f97c4a881b79e86b3ea07cc Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 25 Feb 2022 13:06:42 +0100 Subject: [PATCH 04/27] Remove external assembly (#343) --- Cargo.toml | 11 +- build.rs | 54 ----- src/asm/asm.s | 352 ------------------------------- src/asm/mod.rs | 314 --------------------------- src/instructions/interrupts.rs | 22 -- src/instructions/mod.rs | 18 -- src/instructions/port.rs | 58 +---- src/instructions/segmentation.rs | 35 --- src/instructions/tables.rs | 27 --- src/instructions/tlb.rs | 11 - src/lib.rs | 4 - src/registers/control.rs | 39 ---- src/registers/mod.rs | 2 +- src/registers/model_specific.rs | 31 +-- src/registers/mxcsr.rs | 19 +- src/registers/rflags.rs | 12 -- src/registers/xcontrol.rs | 13 -- 17 files changed, 26 insertions(+), 996 deletions(-) delete mode 100644 build.rs delete mode 100644 src/asm/asm.s delete mode 100644 src/asm/mod.rs diff --git a/Cargo.toml b/Cargo.toml index ffec90e41..187dc6e95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,19 +30,18 @@ bit_field = "0.10.1" bitflags = "1.0.4" volatile = "0.4.4" -[build-dependencies] -cc = { version = "1.0.37", optional = true } - [features] default = [ "nightly", "instructions" ] instructions = [] -external_asm = [ "cc" ] -nightly = [ "inline_asm", "const_fn", "abi_x86_interrupt", "doc_cfg" ] -inline_asm = [] +nightly = [ "const_fn", "abi_x86_interrupt", "doc_cfg" ] abi_x86_interrupt = [] const_fn = [] doc_cfg = [] +# These features are no longer used and only there for backwards compatibility. +external_asm = [] +inline_asm = [] + [package.metadata.release] no-dev-version = true pre-release-replacements = [ diff --git a/build.rs b/build.rs deleted file mode 100644 index 21c783bad..000000000 --- a/build.rs +++ /dev/null @@ -1,54 +0,0 @@ -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - - #[cfg(all(feature = "external_asm", windows))] - compile_error!("\"external_asm\" feature is not available on windows toolchain!"); - - #[cfg(feature = "instructions")] - if std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() != "x86_64" { - panic!("\"instructions\" feature is only available for x86_64 targets!"); - } - - #[cfg(all( - feature = "instructions", - not(feature = "inline_asm"), - not(feature = "external_asm") - ))] - compile_error!("\"instructions\" feature is enabled, but neither feature \"external_asm\" nor \"inline_asm\" was set!"); - - #[cfg(all(feature = "inline_asm", feature = "external_asm"))] - compile_error!( - "\"inline_asm\" and \"external_asm\" features can not be enabled at the same time!" - ); - - #[cfg(all(feature = "instructions", feature = "external_asm"))] - { - use std::ffi::OsString; - use std::fs; - - let entries = fs::read_dir("src/asm") - .unwrap() - .filter_map(|f| { - f.ok().and_then(|e| { - let path = e.path(); - match path.extension() { - Some(ext) if ext.eq(&OsString::from("s")) => Some(path), - _ => None, - } - }) - }) - .collect::>(); - - cc::Build::new() - .no_default_flags(true) - .files(&entries) - .pic(true) - .static_flag(true) - .shared_flag(false) - .compile("x86_64_asm"); - - for e in entries { - println!("cargo:rerun-if-changed={}", e.to_str().unwrap()); - } - } -} diff --git a/src/asm/asm.s b/src/asm/asm.s deleted file mode 100644 index 831828a82..000000000 --- a/src/asm/asm.s +++ /dev/null @@ -1,352 +0,0 @@ -.text -.code64 - -# REMEMBER: This code uses the AMD64 calling convention: -# Arguments: RDI, RSI, RDX, RCX -# Return: RAX - -.global _x86_64_asm_interrupt_enable -.p2align 4 -_x86_64_asm_interrupt_enable: - sti - retq - -.global _x86_64_asm_interrupt_disable -.p2align 4 -_x86_64_asm_interrupt_disable: - cli - retq - -.global _x86_64_asm_interrupt_enable_and_hlt -.p2align 4 -_x86_64_asm_interrupt_enable_and_hlt: - sti - hlt - retq - -.global _x86_64_asm_int3 -.p2align 4 -_x86_64_asm_int3: - int3 - retq - -.global _x86_64_asm_read_from_port_u8 -.p2align 4 -_x86_64_asm_read_from_port_u8: - mov %edi, %edx - inb (%dx), %al - retq - -.global _x86_64_asm_read_from_port_u16 -.p2align 4 -_x86_64_asm_read_from_port_u16: - mov %edi, %edx - inw (%dx), %ax - retq - -.global _x86_64_asm_read_from_port_u32 -.p2align 4 -_x86_64_asm_read_from_port_u32: - mov %edi, %edx - inl (%dx), %eax - retq - - -.global _x86_64_asm_write_to_port_u8 -.p2align 4 -_x86_64_asm_write_to_port_u8: - mov %edi, %edx - mov %si, %ax - outb %al, (%dx) - retq - -.global _x86_64_asm_write_to_port_u16 -.p2align 4 -_x86_64_asm_write_to_port_u16: - mov %edi, %edx - mov %si, %ax - outw %ax, (%dx) - retq - -.global _x86_64_asm_write_to_port_u32 -.p2align 4 -_x86_64_asm_write_to_port_u32: - mov %edi, %edx - mov %esi, %eax - outl %eax, (%dx) - retq - -.global _x86_64_asm_set_cs -.p2align 4 -_x86_64_asm_set_cs: - pushq %rdi - leaq 1f(%rip), %rax - pushq %rax - lretq -1: - retq - -.global _x86_64_asm_get_cs -.p2align 4 -_x86_64_asm_get_cs: - mov %cs, %ax - retq - -.global _x86_64_asm_invlpg -.p2align 4 -_x86_64_asm_invlpg: - invlpg (%rdi) - retq - -.global _x86_64_asm_invpcid -.p2align 4 -_x86_64_asm_invpcid: - invpcid (%rsi), %rdi - retq - -.global _x86_64_asm_ltr -.p2align 4 -_x86_64_asm_ltr: - mov %edi, %edx - ltr %dx - retq - -.global _x86_64_asm_lgdt -.p2align 4 -_x86_64_asm_lgdt: - lgdt (%rdi) - retq - -.global _x86_64_asm_lidt -.p2align 4 -_x86_64_asm_lidt: - lidt (%rdi) - retq - -.global _x86_64_asm_sgdt -.p2align 4 -_x86_64_asm_sgdt: - sgdt (%rdi) - retq - -.global _x86_64_asm_sidt -.p2align 4 -_x86_64_asm_sidt: - sidt (%rdi) - retq - -.global _x86_64_asm_write_rflags -.p2align 4 -_x86_64_asm_write_rflags: - pushq %rdi - popfq - retq - -.global _x86_64_asm_read_rflags -.p2align 4 -_x86_64_asm_read_rflags: - pushfq - popq %rax - retq - -.global _x86_64_asm_load_ss -.p2align 4 -_x86_64_asm_load_ss: - mov %di, %ss - retq - -.global _x86_64_asm_load_ds -.p2align 4 -_x86_64_asm_load_ds: - mov %di, %ds - retq - -.global _x86_64_asm_load_es -.p2align 4 -_x86_64_asm_load_es: - mov %di, %es - retq - -.global _x86_64_asm_load_fs -.p2align 4 -_x86_64_asm_load_fs: - mov %di, %fs - retq - -.global _x86_64_asm_load_gs -.p2align 4 -_x86_64_asm_load_gs: - mov %di, %gs - retq - -.global _x86_64_asm_get_ss -.p2align 4 -_x86_64_asm_get_ss: - mov %ss, %ax - retq - -.global _x86_64_asm_get_ds -.p2align 4 -_x86_64_asm_get_ds: - mov %ds, %ax - retq - -.global _x86_64_asm_get_es -.p2align 4 -_x86_64_asm_get_es: - mov %es, %ax - retq - -.global _x86_64_asm_get_fs -.p2align 4 -_x86_64_asm_get_fs: - mov %fs, %ax - retq - -.global _x86_64_asm_get_gs -.p2align 4 -_x86_64_asm_get_gs: - mov %gs, %ax - retq - -.global _x86_64_asm_swapgs -.p2align 4 -_x86_64_asm_swapgs: - swapgs - retq - -.global _x86_64_asm_read_cr0 -.p2align 4 -_x86_64_asm_read_cr0: - movq %cr0, %rax - retq - -.global _x86_64_asm_read_cr2 -.p2align 4 -_x86_64_asm_read_cr2: - movq %cr2, %rax - retq - -.global _x86_64_asm_read_cr3 -.p2align 4 -_x86_64_asm_read_cr3: - movq %cr3, %rax - retq - -.global _x86_64_asm_read_cr4 -.p2align 4 -_x86_64_asm_read_cr4: - movq %cr4, %rax - retq - -.global _x86_64_asm_write_cr0 -.p2align 4 -_x86_64_asm_write_cr0: - movq %rdi, %cr0 - retq - -.global _x86_64_asm_write_cr3 -.p2align 4 -_x86_64_asm_write_cr3: - movq %rdi, %cr3 - retq - -.global _x86_64_asm_write_cr4 -.p2align 4 -_x86_64_asm_write_cr4: - movq %rdi, %cr4 - retq - -.global _x86_64_asm_rdmsr -.p2align 4 -_x86_64_asm_rdmsr: - mov %edi, %ecx # First param is the MSR number - rdmsr - shl $32, %rdx # shift edx to upper 32bit - mov %eax, %eax # clear upper 32bit of rax - or %rdx, %rax # or with rdx - retq - -.global _x86_64_asm_wrmsr -.p2align 4 -_x86_64_asm_wrmsr: - movl %edi, %ecx # First param is the MSR number - movl %esi, %eax # Second param is the low 32-bits - wrmsr # Third param (high 32-bits) is already in %edx - retq - -.global _x86_64_asm_hlt -.p2align 4 -_x86_64_asm_hlt: - hlt - retq - -.global _x86_64_asm_nop -.p2align 4 -_x86_64_asm_nop: - nop - retq - -.global _x86_64_asm_bochs -.p2align 4 -_x86_64_asm_bochs: - xchgw %bx, %bx - retq - -.global _x86_64_asm_rdfsbase -.p2align 4 -_x86_64_asm_rdfsbase: - rdfsbase %rax - retq - -.global _x86_64_asm_wrfsbase -.p2align 4 -_x86_64_asm_wrfsbase: - wrfsbase %rdi - retq - -.global _x86_64_asm_rdgsbase -.p2align 4 -_x86_64_asm_rdgsbase: - rdgsbase %rax - retq - -.global _x86_64_asm_wrgsbase -.p2align 4 -_x86_64_asm_wrgsbase: - wrgsbase %rdi - retq - -.global _x86_64_asm_xgetbv -.p2align 4 -_x86_64_asm_xgetbv: - mov %edi, %ecx # First param is the XCR number - xgetbv - shl $32, %rdx # shift edx to upper 32bit - mov %eax, %eax # clear upper 32bit of rax - or %rdx, %rax # or with rdx - retq - -.global _x86_64_asm_xsetbv -.p2align 4 -_x86_64_asm_xsetbv: - movl %edi, %ecx # First param is the XCR number - movl %esi, %eax # Second param is the low 32-bits - xsetbv # Third param (high 32-bits) is already in %edx - retq - -.global _x86_64_asm_write_mxcsr -.p2align 4 -_x86_64_asm_write_mxcsr: - pushq %rdi - ldmxcsr (%rsp) - popq %rdi - retq - -.global _x86_64_asm_read_mxcsr -.p2align 4 -_x86_64_asm_read_mxcsr: - pushq $0 - stmxcsr (%rsp) - popq %rax - retq diff --git a/src/asm/mod.rs b/src/asm/mod.rs deleted file mode 100644 index 6d481dad9..000000000 --- a/src/asm/mod.rs +++ /dev/null @@ -1,314 +0,0 @@ -#[link(name = "x86_64_asm", kind = "static")] -extern "sysv64" { - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_interrupt_enable" - )] - pub(crate) fn x86_64_asm_interrupt_enable(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_interrupt_disable" - )] - pub(crate) fn x86_64_asm_interrupt_disable(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_interrupt_enable_and_hlt" - )] - pub(crate) fn x86_64_asm_interrupt_enable_and_hlt(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_int3" - )] - pub(crate) fn x86_64_asm_int3(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_hlt" - )] - pub(crate) fn x86_64_asm_hlt(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_nop" - )] - pub(crate) fn x86_64_asm_nop(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_bochs" - )] - pub(crate) fn x86_64_asm_bochs(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_from_port_u8" - )] - pub(crate) fn x86_64_asm_read_from_port_u8(port: u16) -> u8; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_from_port_u16" - )] - pub(crate) fn x86_64_asm_read_from_port_u16(port: u16) -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_from_port_u32" - )] - pub(crate) fn x86_64_asm_read_from_port_u32(port: u16) -> u32; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_to_port_u8" - )] - pub(crate) fn x86_64_asm_write_to_port_u8(port: u16, value: u8); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_to_port_u16" - )] - pub(crate) fn x86_64_asm_write_to_port_u16(port: u16, value: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_to_port_u32" - )] - pub(crate) fn x86_64_asm_write_to_port_u32(port: u16, value: u32); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_set_cs" - )] - pub(crate) fn x86_64_asm_set_cs(sel: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_load_ss" - )] - pub(crate) fn x86_64_asm_load_ss(sel: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_load_ds" - )] - pub(crate) fn x86_64_asm_load_ds(sel: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_load_es" - )] - pub(crate) fn x86_64_asm_load_es(sel: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_load_fs" - )] - pub(crate) fn x86_64_asm_load_fs(sel: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_load_gs" - )] - pub(crate) fn x86_64_asm_load_gs(sel: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_get_ss" - )] - pub(crate) fn x86_64_asm_get_ss() -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_get_ds" - )] - pub(crate) fn x86_64_asm_get_ds() -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_get_es" - )] - pub(crate) fn x86_64_asm_get_es() -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_get_fs" - )] - pub(crate) fn x86_64_asm_get_fs() -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_get_gs" - )] - pub(crate) fn x86_64_asm_get_gs() -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_swapgs" - )] - pub(crate) fn x86_64_asm_swapgs(); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_get_cs" - )] - pub(crate) fn x86_64_asm_get_cs() -> u16; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_lgdt" - )] - pub(crate) fn x86_64_asm_lgdt(gdt: *const crate::instructions::tables::DescriptorTablePointer); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_lidt" - )] - pub(crate) fn x86_64_asm_lidt(idt: *const crate::instructions::tables::DescriptorTablePointer); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_sgdt" - )] - pub(crate) fn x86_64_asm_sgdt(gdt: *mut crate::instructions::tables::DescriptorTablePointer); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_sidt" - )] - pub(crate) fn x86_64_asm_sidt(idt: *mut crate::instructions::tables::DescriptorTablePointer); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_ltr" - )] - pub(crate) fn x86_64_asm_ltr(sel: u16); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_invlpg" - )] - pub(crate) fn x86_64_asm_invlpg(addr: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_invpcid" - )] - pub(crate) fn x86_64_asm_invpcid(kind: u64, desc: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_cr0" - )] - pub(crate) fn x86_64_asm_read_cr0() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_cr0" - )] - pub(crate) fn x86_64_asm_write_cr0(value: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_cr2" - )] - pub(crate) fn x86_64_asm_read_cr2() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_cr3" - )] - pub(crate) fn x86_64_asm_read_cr3() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_cr3" - )] - pub(crate) fn x86_64_asm_write_cr3(value: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_cr4" - )] - pub(crate) fn x86_64_asm_read_cr4() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_cr4" - )] - pub(crate) fn x86_64_asm_write_cr4(value: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_rdmsr" - )] - pub(crate) fn x86_64_asm_rdmsr(msr: u32) -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_wrmsr" - )] - pub(crate) fn x86_64_asm_wrmsr(msr: u32, low: u32, high: u32); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_rflags" - )] - pub(crate) fn x86_64_asm_read_rflags() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_rflags" - )] - pub(crate) fn x86_64_asm_write_rflags(val: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_rdfsbase" - )] - pub(crate) fn x86_64_asm_rdfsbase() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_wrfsbase" - )] - pub(crate) fn x86_64_asm_wrfsbase(val: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_rdgsbase" - )] - pub(crate) fn x86_64_asm_rdgsbase() -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_wrgsbase" - )] - pub(crate) fn x86_64_asm_wrgsbase(val: u64); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_xgetbv" - )] - pub(crate) fn x86_64_asm_xgetbv(xcr: u32) -> u64; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_xsetbv" - )] - pub(crate) fn x86_64_asm_xsetbv(xcr: u32, low: u32, high: u32); - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_read_mxcsr" - )] - pub(crate) fn x86_64_asm_read_mxcsr() -> u32; - - #[cfg_attr( - any(target_env = "gnu", target_env = "musl"), - link_name = "_x86_64_asm_write_mxcsr" - )] - pub(crate) fn x86_64_asm_write_mxcsr(val: u32); -} diff --git a/src/instructions/interrupts.rs b/src/instructions/interrupts.rs index d850cf0f3..6f0cd8381 100644 --- a/src/instructions/interrupts.rs +++ b/src/instructions/interrupts.rs @@ -1,6 +1,5 @@ //! Enabling and disabling interrupts -#[cfg(feature = "inline_asm")] use core::arch::asm; /// Returns whether interrupts are enabled. @@ -17,11 +16,7 @@ pub fn are_enabled() -> bool { #[inline] pub fn enable() { unsafe { - #[cfg(feature = "inline_asm")] asm!("sti", options(nomem, nostack)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_interrupt_enable(); } } @@ -31,11 +26,7 @@ pub fn enable() { #[inline] pub fn disable() { unsafe { - #[cfg(feature = "inline_asm")] asm!("cli", options(nomem, nostack)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_interrupt_disable(); } } @@ -130,11 +121,7 @@ where #[inline] pub fn enable_and_hlt() { unsafe { - #[cfg(feature = "inline_asm")] asm!("sti; hlt", options(nomem, nostack)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_interrupt_enable_and_hlt(); } } @@ -142,11 +129,7 @@ pub fn enable_and_hlt() { #[inline] pub fn int3() { unsafe { - #[cfg(feature = "inline_asm")] asm!("int3", options(nomem, nostack)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_int3(); } } @@ -155,11 +138,6 @@ pub fn int3() { /// This currently needs to be a macro because the `int` argument needs to be an /// immediate. This macro will be replaced by a generic function when support for /// const generics is implemented in Rust. -#[cfg(feature = "inline_asm")] -#[cfg_attr( - feature = "doc_cfg", - doc(cfg(any(feature = "nightly", feature = "inline_asm"))) -)] #[macro_export] macro_rules! software_interrupt { ($x:expr) => {{ diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index bd35f2a82..984c13284 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -9,18 +9,13 @@ pub mod segmentation; pub mod tables; pub mod tlb; -#[cfg(feature = "inline_asm")] use core::arch::asm; /// Halts the CPU until the next interrupt arrives. #[inline] pub fn hlt() { unsafe { - #[cfg(feature = "inline_asm")] asm!("hlt", options(nomem, nostack, preserves_flags)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_hlt(); } } @@ -33,11 +28,7 @@ pub fn hlt() { #[inline] pub fn nop() { unsafe { - #[cfg(feature = "inline_asm")] asm!("nop", options(nomem, nostack, preserves_flags)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_nop(); } } @@ -46,21 +37,12 @@ pub fn nop() { #[inline] pub fn bochs_breakpoint() { unsafe { - #[cfg(feature = "inline_asm")] asm!("xchg bx, bx", options(nomem, nostack, preserves_flags)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_bochs(); } } /// Gets the current instruction pointer. Note that this is only approximate as it requires a few /// instructions to execute. -#[cfg(feature = "inline_asm")] -#[cfg_attr( - feature = "doc_cfg", - doc(cfg(any(feature = "nightly", feature = "inline_asm"))) -)] #[inline(always)] pub fn read_rip() -> crate::VirtAddr { let rip: u64; diff --git a/src/instructions/port.rs b/src/instructions/port.rs index b23be4401..0263d0e0e 100644 --- a/src/instructions/port.rs +++ b/src/instructions/port.rs @@ -1,6 +1,5 @@ //! Access to I/O ports -#[cfg(feature = "inline_asm")] use core::arch::asm; use core::fmt; use core::marker::PhantomData; @@ -10,99 +9,60 @@ pub use crate::structures::port::{PortRead, PortWrite}; impl PortRead for u8 { #[inline] unsafe fn read_from_port(port: u16) -> u8 { - #[cfg(feature = "inline_asm")] - { - let value: u8; - unsafe { - asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags)); - } - value - } - #[cfg(not(feature = "inline_asm"))] + let value: u8; unsafe { - crate::asm::x86_64_asm_read_from_port_u8(port) + asm!("in al, dx", out("al") value, in("dx") port, options(nomem, nostack, preserves_flags)); } + value } } impl PortRead for u16 { #[inline] unsafe fn read_from_port(port: u16) -> u16 { - #[cfg(feature = "inline_asm")] - { - let value: u16; - unsafe { - asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags)); - } - value - } - #[cfg(not(feature = "inline_asm"))] + let value: u16; unsafe { - crate::asm::x86_64_asm_read_from_port_u16(port) + asm!("in ax, dx", out("ax") value, in("dx") port, options(nomem, nostack, preserves_flags)); } + value } } impl PortRead for u32 { #[inline] unsafe fn read_from_port(port: u16) -> u32 { - #[cfg(feature = "inline_asm")] - { - let value: u32; - unsafe { - asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags)); - } - value - } - #[cfg(not(feature = "inline_asm"))] + let value: u32; unsafe { - crate::asm::x86_64_asm_read_from_port_u32(port) + asm!("in eax, dx", out("eax") value, in("dx") port, options(nomem, nostack, preserves_flags)); } + value } } impl PortWrite for u8 { #[inline] unsafe fn write_to_port(port: u16, value: u8) { - #[cfg(feature = "inline_asm")] unsafe { asm!("out dx, al", in("dx") port, in("al") value, options(nomem, nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_to_port_u8(port, value); - } } } impl PortWrite for u16 { #[inline] unsafe fn write_to_port(port: u16, value: u16) { - #[cfg(feature = "inline_asm")] unsafe { asm!("out dx, ax", in("dx") port, in("ax") value, options(nomem, nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_to_port_u16(port, value); - } } } impl PortWrite for u32 { #[inline] unsafe fn write_to_port(port: u16, value: u32) { - #[cfg(feature = "inline_asm")] unsafe { asm!("out dx, eax", in("dx") port, in("eax") value, options(nomem, nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_to_port_u32(port, value); - } } } diff --git a/src/instructions/segmentation.rs b/src/instructions/segmentation.rs index fda49eec7..334c42237 100644 --- a/src/instructions/segmentation.rs +++ b/src/instructions/segmentation.rs @@ -6,21 +6,15 @@ use crate::{ structures::gdt::SegmentSelector, VirtAddr, }; -#[cfg(feature = "inline_asm")] use core::arch::asm; macro_rules! get_reg_impl { ($name:literal, $asm_get:ident) => { fn get_reg() -> SegmentSelector { let segment: u16; - #[cfg(feature = "inline_asm")] unsafe { asm!(concat!("mov {0:x}, ", $name), out(reg) segment, options(nomem, nostack, preserves_flags)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - segment = crate::asm::$asm_get(); - } SegmentSelector(segment) } }; @@ -32,15 +26,9 @@ macro_rules! segment_impl { get_reg_impl!($name, $asm_get); unsafe fn set_reg(sel: SegmentSelector) { - #[cfg(feature = "inline_asm")] unsafe { asm!(concat!("mov ", $name, ", {0:x}"), in(reg) sel.0, options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe{ - crate::asm::$asm_load(sel.0); - } } } }; @@ -51,28 +39,17 @@ macro_rules! segment64_impl { impl Segment64 for $type { const BASE: Msr = <$base>::MSR; fn read_base() -> VirtAddr { - #[cfg(feature = "inline_asm")] unsafe { let val: u64; asm!(concat!("rd", $name, "base {}"), out(reg) val, options(nomem, nostack, preserves_flags)); VirtAddr::new_unsafe(val) } - #[cfg(not(feature = "inline_asm"))] - unsafe { - VirtAddr::new_unsafe(crate::asm::$asm_rd()) - } } unsafe fn write_base(base: VirtAddr) { - #[cfg(feature = "inline_asm")] unsafe{ asm!(concat!("wr", $name, "base {}"), in(reg) base.as_u64(), options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe{ - crate::asm::$asm_wr(base.as_u64()); - } } } }; @@ -90,7 +67,6 @@ impl Segment for CS { /// would only be able to jump to 32-bit instruction pointers. Only Intel implements support /// for 64-bit far calls/jumps in long-mode, AMD does not. unsafe fn set_reg(sel: SegmentSelector) { - #[cfg(feature = "inline_asm")] unsafe { asm!( "push {sel}", @@ -103,11 +79,6 @@ impl Segment for CS { options(preserves_flags), ); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_set_cs(u64::from(sel.0)); - } } } @@ -127,15 +98,9 @@ impl GS { /// This function is unsafe because the caller must ensure that the /// swap operation cannot lead to undefined behavior. pub unsafe fn swap() { - #[cfg(feature = "inline_asm")] unsafe { asm!("swapgs", options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_swapgs(); - } } } diff --git a/src/instructions/tables.rs b/src/instructions/tables.rs index 28cb4faf5..5139df7ac 100644 --- a/src/instructions/tables.rs +++ b/src/instructions/tables.rs @@ -2,7 +2,6 @@ use crate::structures::gdt::SegmentSelector; use crate::VirtAddr; -#[cfg(feature = "inline_asm")] use core::arch::asm; pub use crate::structures::DescriptorTablePointer; @@ -20,15 +19,9 @@ pub use crate::structures::DescriptorTablePointer; /// GDT is safe. #[inline] pub unsafe fn lgdt(gdt: &DescriptorTablePointer) { - #[cfg(feature = "inline_asm")] unsafe { asm!("lgdt [{}]", in(reg) gdt, options(readonly, nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_lgdt(gdt as *const _); - } } /// Load an IDT. @@ -44,15 +37,9 @@ pub unsafe fn lgdt(gdt: &DescriptorTablePointer) { /// IDT is safe. #[inline] pub unsafe fn lidt(idt: &DescriptorTablePointer) { - #[cfg(feature = "inline_asm")] unsafe { asm!("lidt [{}]", in(reg) idt, options(readonly, nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_lidt(idt as *const _); - } } /// Get the address of the current GDT. @@ -63,11 +50,7 @@ pub fn sgdt() -> DescriptorTablePointer { base: VirtAddr::new(0), }; unsafe { - #[cfg(feature = "inline_asm")] asm!("sgdt [{}]", in(reg) &mut gdt, options(nostack, preserves_flags)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_sgdt(&mut gdt as *mut _); } gdt } @@ -80,11 +63,7 @@ pub fn sidt() -> DescriptorTablePointer { base: VirtAddr::new(0), }; unsafe { - #[cfg(feature = "inline_asm")] asm!("sidt [{}]", in(reg) &mut idt, options(nostack, preserves_flags)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_sidt(&mut idt as *mut _); } idt } @@ -98,13 +77,7 @@ pub fn sidt() -> DescriptorTablePointer { /// this TSS is safe. #[inline] pub unsafe fn load_tss(sel: SegmentSelector) { - #[cfg(feature = "inline_asm")] unsafe { asm!("ltr {0:x}", in(reg) sel.0, options(nomem, nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_ltr(sel.0); - } } diff --git a/src/instructions/tlb.rs b/src/instructions/tlb.rs index a45cf9f66..b300a2a74 100644 --- a/src/instructions/tlb.rs +++ b/src/instructions/tlb.rs @@ -1,18 +1,13 @@ //! Functions to flush the translation lookaside buffer (TLB). use crate::VirtAddr; -#[cfg(feature = "inline_asm")] use core::arch::asm; /// Invalidate the given address in the TLB using the `invlpg` instruction. #[inline] pub fn flush(addr: VirtAddr) { unsafe { - #[cfg(feature = "inline_asm")] asm!("invlpg [{}]", in(reg) addr.as_u64(), options(nostack, preserves_flags)); - - #[cfg(not(feature = "inline_asm"))] - crate::asm::x86_64_asm_invlpg(addr.as_u64()); } } @@ -98,13 +93,7 @@ pub unsafe fn flush_pcid(command: InvPicdCommand) { InvPicdCommand::AllExceptGlobal => kind = 3, } - #[cfg(feature = "inline_asm")] unsafe { asm!("invpcid {0}, [{1}]", in(reg) kind, in(reg) &desc, options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_invpcid(kind, &desc as *const _ as u64); - } } diff --git a/src/lib.rs b/src/lib.rs index ed086a522..cc47b745b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ #![cfg_attr(feature = "const_fn", feature(const_mut_refs))] // GDT add_entry() #![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))] // IDT new() #![cfg_attr(feature = "const_fn", feature(const_fn_trait_bound))] // PageSize marker trait -#![cfg_attr(feature = "inline_asm", feature(asm))] #![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))] #![cfg_attr(feature = "doc_cfg", feature(doc_cfg))] #![warn(missing_docs)] @@ -45,9 +44,6 @@ macro_rules! const_fn { }; } -#[cfg(all(feature = "instructions", feature = "external_asm"))] -pub(crate) mod asm; - pub mod addr; pub mod instructions; pub mod registers; diff --git a/src/registers/control.rs b/src/registers/control.rs index bd2b06316..56fb987aa 100644 --- a/src/registers/control.rs +++ b/src/registers/control.rs @@ -161,7 +161,6 @@ bitflags! { mod x86_64 { use super::*; use crate::{instructions::tlb::Pcid, structures::paging::PhysFrame, PhysAddr, VirtAddr}; - #[cfg(feature = "inline_asm")] use core::arch::asm; impl Cr0 { @@ -176,14 +175,9 @@ mod x86_64 { pub fn read_raw() -> u64 { let value: u64; - #[cfg(feature = "inline_asm")] unsafe { asm!("mov {}, cr0", out(reg) value, options(nomem, nostack, preserves_flags)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - value = crate::asm::x86_64_asm_read_cr0(); - } value } @@ -217,15 +211,9 @@ mod x86_64 { /// safety through it, e.g. by disabling paging. #[inline] pub unsafe fn write_raw(value: u64) { - #[cfg(feature = "inline_asm")] unsafe { asm!("mov cr0, {}", in(reg) value, options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_cr0(value); - } } /// Updates CR0 flags. @@ -261,14 +249,9 @@ mod x86_64 { pub fn read_raw() -> u64 { let value: u64; - #[cfg(feature = "inline_asm")] unsafe { asm!("mov {}, cr2", out(reg) value, options(nomem, nostack, preserves_flags)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - value = crate::asm::x86_64_asm_read_cr2(); - } value } @@ -288,14 +271,9 @@ mod x86_64 { pub fn read_raw() -> (PhysFrame, u16) { let value: u64; - #[cfg(feature = "inline_asm")] unsafe { asm!("mov {}, cr3", out(reg) value, options(nomem, nostack, preserves_flags)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - value = crate::asm::x86_64_asm_read_cr3(); - } let addr = PhysAddr::new(value & 0x_000f_ffff_ffff_f000); let frame = PhysFrame::containing_address(addr); @@ -349,15 +327,9 @@ mod x86_64 { let addr = frame.start_address(); let value = addr.as_u64() | val as u64; - #[cfg(feature = "inline_asm")] unsafe { asm!("mov cr3, {}", in(reg) value, options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_cr3(value) - } } } @@ -373,14 +345,9 @@ mod x86_64 { pub fn read_raw() -> u64 { let value: u64; - #[cfg(feature = "inline_asm")] unsafe { asm!("mov {}, cr4", out(reg) value, options(nomem, nostack, preserves_flags)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - value = crate::asm::x86_64_asm_read_cr4(); - } value } @@ -416,15 +383,9 @@ mod x86_64 { /// flag. #[inline] pub unsafe fn write_raw(value: u64) { - #[cfg(feature = "inline_asm")] unsafe { asm!("mov cr4, {}", in(reg) value, options(nostack, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_cr4(value); - } } /// Updates CR4 flags. diff --git a/src/registers/mod.rs b/src/registers/mod.rs index 68ab57081..dfde2439a 100644 --- a/src/registers/mod.rs +++ b/src/registers/mod.rs @@ -11,5 +11,5 @@ pub mod xcontrol; #[allow(deprecated)] pub use crate::instructions::segmentation::{rdfsbase, rdgsbase, wrfsbase, wrgsbase}; -#[cfg(all(feature = "instructions", feature = "inline_asm"))] +#[cfg(feature = "instructions")] pub use crate::instructions::read_rip; diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index a2d285d00..4f55ece89 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -127,7 +127,6 @@ mod x86_64 { control::Cr4Flags, segmentation::{Segment, Segment64, CS, SS}, }; - #[cfg(feature = "inline_asm")] use core::arch::asm; impl Msr { @@ -139,24 +138,16 @@ mod x86_64 { /// effects. #[inline] pub unsafe fn read(&self) -> u64 { - #[cfg(feature = "inline_asm")] - { - let (high, low): (u32, u32); - unsafe { - asm!( - "rdmsr", - in("ecx") self.0, - out("eax") low, out("edx") high, - options(nomem, nostack, preserves_flags), - ); - } - ((high as u64) << 32) | (low as u64) - } - - #[cfg(not(feature = "inline_asm"))] + let (high, low): (u32, u32); unsafe { - crate::asm::x86_64_asm_rdmsr(self.0) + asm!( + "rdmsr", + in("ecx") self.0, + out("eax") low, out("edx") high, + options(nomem, nostack, preserves_flags), + ); } + ((high as u64) << 32) | (low as u64) } /// Write 64 bits to msr register. @@ -170,7 +161,6 @@ mod x86_64 { let low = value as u32; let high = (value >> 32) as u32; - #[cfg(feature = "inline_asm")] unsafe { asm!( "wrmsr", @@ -179,11 +169,6 @@ mod x86_64 { options(nostack, preserves_flags), ); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_wrmsr(self.0, low, high); - } } } diff --git a/src/registers/mxcsr.rs b/src/registers/mxcsr.rs index f10812b31..ecb13a933 100644 --- a/src/registers/mxcsr.rs +++ b/src/registers/mxcsr.rs @@ -62,37 +62,24 @@ impl Default for MxCsr { #[cfg(feature = "instructions")] mod x86_64 { use super::*; - #[cfg(feature = "inline_asm")] use core::arch::asm; /// Read the value of MXCSR. #[inline] pub fn read() -> MxCsr { - #[cfg(feature = "inline_asm")] - { - let mut mxcsr: u32 = 0; - unsafe { - asm!("stmxcsr [{}]", in(reg) &mut mxcsr, options(nostack, preserves_flags)); - } - MxCsr::from_bits_truncate(mxcsr) - } - #[cfg(not(feature = "inline_asm"))] + let mut mxcsr: u32 = 0; unsafe { - MxCsr::from_bits_truncate(crate::asm::x86_64_asm_read_mxcsr()) + asm!("stmxcsr [{}]", in(reg) &mut mxcsr, options(nostack, preserves_flags)); } + MxCsr::from_bits_truncate(mxcsr) } /// Write MXCSR. #[inline] pub fn write(mxcsr: MxCsr) { - #[cfg(feature = "inline_asm")] unsafe { asm!("ldmxcsr [{}]", in(reg) &mxcsr, options(nostack, readonly)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_mxcsr(mxcsr.bits()); - } } #[cfg(test)] diff --git a/src/registers/rflags.rs b/src/registers/rflags.rs index 4a0c8df3d..1a44365b8 100644 --- a/src/registers/rflags.rs +++ b/src/registers/rflags.rs @@ -65,7 +65,6 @@ bitflags! { #[cfg(feature = "instructions")] mod x86_64 { use super::*; - #[cfg(feature = "inline_asm")] use core::arch::asm; /// Returns the current value of the RFLAGS register. @@ -81,14 +80,9 @@ mod x86_64 { pub fn read_raw() -> u64 { let r: u64; - #[cfg(feature = "inline_asm")] unsafe { asm!("pushfq; pop {}", out(reg) r, options(nomem, preserves_flags)); } - #[cfg(not(feature = "inline_asm"))] - unsafe { - r = crate::asm::x86_64_asm_read_rflags(); - } r } @@ -125,15 +119,9 @@ mod x86_64 { pub unsafe fn write_raw(val: u64) { // HACK: we mark this function as preserves_flags to prevent Rust from restoring // saved flags after the "popf" below. See above note on safety. - #[cfg(feature = "inline_asm")] unsafe { asm!("push {}; popfq", in(reg) val, options(nomem, preserves_flags)); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_write_rflags(val); - } } #[cfg(test)] diff --git a/src/registers/xcontrol.rs b/src/registers/xcontrol.rs index 3f85001c3..655e4ea9d 100644 --- a/src/registers/xcontrol.rs +++ b/src/registers/xcontrol.rs @@ -54,7 +54,6 @@ bitflags! { #[cfg(feature = "instructions")] mod x86_64 { use super::*; - #[cfg(feature = "inline_asm")] use core::arch::asm; impl XCr0 { @@ -67,7 +66,6 @@ mod x86_64 { /// Read the current raw XCR0 value. #[inline] pub fn read_raw() -> u64 { - #[cfg(feature = "inline_asm")] unsafe { let (low, high): (u32, u32); asm!( @@ -78,11 +76,6 @@ mod x86_64 { ); (high as u64) << 32 | (low as u64) } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_xgetbv(0) - } } /// Write XCR0 flags. @@ -144,7 +137,6 @@ mod x86_64 { let low = value as u32; let high = (value >> 32) as u32; - #[cfg(feature = "inline_asm")] unsafe { asm!( "xsetbv", @@ -153,11 +145,6 @@ mod x86_64 { options(nomem, nostack, preserves_flags), ); } - - #[cfg(not(feature = "inline_asm"))] - unsafe { - crate::asm::x86_64_asm_xsetbv(0, low, high); - } } } } From 36809076b7144fe0d40b22110ace132c330c2a99 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 12 Feb 2022 16:02:02 +0100 Subject: [PATCH 05/27] implement `Step` for `VirtAddr` --- Cargo.toml | 3 +- src/addr.rs | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 187dc6e95..71f0d1de3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,9 +33,10 @@ volatile = "0.4.4" [features] default = [ "nightly", "instructions" ] instructions = [] -nightly = [ "const_fn", "abi_x86_interrupt", "doc_cfg" ] +nightly = [ "const_fn", "step_trait", "abi_x86_interrupt", "doc_cfg" ] abi_x86_interrupt = [] const_fn = [] +step_trait = [] doc_cfg = [] # These features are no longer used and only there for backwards compatibility. diff --git a/src/addr.rs b/src/addr.rs index 74f677453..bcf72c8f9 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -1,6 +1,10 @@ //! Physical and virtual addresses manipulation +#[cfg(feature = "step_trait")] +use core::convert::TryFrom; use core::fmt; +#[cfg(feature = "step_trait")] +use core::iter::Step; use core::ops::{Add, AddAssign, Sub, SubAssign}; use crate::structures::paging::page_table::PageTableLevel; @@ -322,6 +326,44 @@ impl Sub for VirtAddr { } } +#[cfg(feature = "step_trait")] +impl Step for VirtAddr { + fn steps_between(start: &Self, end: &Self) -> Option { + let mut steps = end.0.checked_sub(start.0)?; + + // Check if we jumped the gap. + if end.0.get_bit(47) && !start.0.get_bit(47) { + steps -= 0xffff_0000_0000_0000; + } + + usize::try_from(steps).ok() + } + + fn forward_checked(start: Self, count: usize) -> Option { + let offset = u64::try_from(count).ok()?; + let mut addr = start.0.checked_add(offset)?; + + // Jump the gap by sign extending the 47th bit. + if addr.get_bits(47..) == 0x1 { + addr.set_bits(47.., 0x1ffff); + } + + Some(Self(addr)) + } + + fn backward_checked(start: Self, count: usize) -> Option { + let offset = u64::try_from(count).ok()?; + let mut addr = start.0.checked_sub(offset)?; + + // Jump the gap by sign extending the 47th bit. + if addr.get_bits(47..) == 0x1fffe { + addr.set_bits(47.., 0); + } + + Some(Self(addr)) + } +} + /// A passed `u64` was not a valid physical address. /// /// This means that bits 52 to 64 were not all null. @@ -577,6 +619,76 @@ mod tests { assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47)); } + #[test] + #[cfg(feature = "step_trait")] + fn virtaddr_step() { + assert_eq!(Step::forward(VirtAddr(0), 0), VirtAddr(0)); + assert_eq!(Step::forward(VirtAddr(0), 1), VirtAddr(1)); + assert_eq!( + Step::forward(VirtAddr(0x7fff_ffff_ffff), 1), + VirtAddr(0xffff_8000_0000_0000) + ); + assert_eq!( + Step::forward(VirtAddr(0xffff_8000_0000_0000), 1), + VirtAddr(0xffff_8000_0000_0001) + ); + assert_eq!( + Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1), + None + ); + + assert_eq!(Step::backward(VirtAddr(0), 0), VirtAddr(0)); + assert_eq!(Step::backward_checked(VirtAddr(0), 1), None); + assert_eq!(Step::backward(VirtAddr(1), 1), VirtAddr(0)); + assert_eq!( + Step::backward(VirtAddr(0xffff_8000_0000_0000), 1), + VirtAddr(0x7fff_ffff_ffff) + ); + assert_eq!( + Step::backward(VirtAddr(0xffff_8000_0000_0001), 1), + VirtAddr(0xffff_8000_0000_0000) + ); + + assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0)); + assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1)); + assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None); + assert_eq!( + Step::steps_between( + &VirtAddr(0x7fff_ffff_ffff), + &VirtAddr(0xffff_8000_0000_0000) + ), + Some(1) + ); + assert_eq!( + Step::steps_between( + &VirtAddr(0xffff_8000_0000_0000), + &VirtAddr(0x7fff_ffff_ffff) + ), + None + ); + assert_eq!( + Step::steps_between( + &VirtAddr(0xffff_8000_0000_0000), + &VirtAddr(0xffff_8000_0000_0000) + ), + Some(0) + ); + assert_eq!( + Step::steps_between( + &VirtAddr(0xffff_8000_0000_0000), + &VirtAddr(0xffff_8000_0000_0001) + ), + Some(1) + ); + assert_eq!( + Step::steps_between( + &VirtAddr(0xffff_8000_0000_0001), + &VirtAddr(0xffff_8000_0000_0000) + ), + None + ); + } + #[test] pub fn test_align_up() { // align 1 diff --git a/src/lib.rs b/src/lib.rs index cc47b745b..dba7edd1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ #![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))] // IDT new() #![cfg_attr(feature = "const_fn", feature(const_fn_trait_bound))] // PageSize marker trait #![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))] +#![cfg_attr(feature = "step_trait", feature(step_trait))] #![cfg_attr(feature = "doc_cfg", feature(doc_cfg))] #![warn(missing_docs)] #![deny(missing_debug_implementations)] From 6f891df1b3c6cf0c3b824ce263f57fd982ea8921 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sat, 12 Feb 2022 16:15:11 +0100 Subject: [PATCH 06/27] impl `Step` for `Page` --- src/structures/paging/page.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 4a7a9f650..9a538fa0f 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -4,6 +4,8 @@ use crate::structures::paging::page_table::PageTableLevel; use crate::structures::paging::PageTableIndex; use crate::VirtAddr; use core::fmt; +#[cfg(feature = "step_trait")] +use core::iter::Step; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Sub, SubAssign}; @@ -274,6 +276,32 @@ impl Sub for Page { } } +#[cfg(feature = "step_trait")] +impl Step for Page { + fn steps_between(start: &Self, end: &Self) -> Option { + Step::steps_between(&start.start_address, &end.start_address) + .map(|steps| steps / S::SIZE as usize) + } + + fn forward_checked(start: Self, count: usize) -> Option { + let count = count.checked_mul(S::SIZE as usize)?; + let start_address = Step::forward_checked(start.start_address, count)?; + Some(Self { + start_address, + size: PhantomData, + }) + } + + fn backward_checked(start: Self, count: usize) -> Option { + let count = count.checked_mul(S::SIZE as usize)?; + let start_address = Step::backward_checked(start.start_address, count)?; + Some(Self { + start_address, + size: PhantomData, + }) + } +} + /// A range of pages with exclusive upper bound. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[repr(C)] From 7916566d1d4518b4bc05572214fc8d7112cc6e62 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 1 Mar 2022 10:28:15 +0100 Subject: [PATCH 07/27] fix very large steps --- src/addr.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/addr.rs b/src/addr.rs index bcf72c8f9..71e7ee19e 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -11,6 +11,8 @@ use crate::structures::paging::page_table::PageTableLevel; use crate::structures::paging::{PageOffset, PageTableIndex}; use bit_field::BitField; +const ADDRESS_SPACE_SIZE: u64 = 0x1_0000_0000_0000; + /// A canonical 64-bit virtual memory address. /// /// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled @@ -341,6 +343,10 @@ impl Step for VirtAddr { fn forward_checked(start: Self, count: usize) -> Option { let offset = u64::try_from(count).ok()?; + if offset > ADDRESS_SPACE_SIZE { + return None; + } + let mut addr = start.0.checked_add(offset)?; // Jump the gap by sign extending the 47th bit. @@ -353,6 +359,10 @@ impl Step for VirtAddr { fn backward_checked(start: Self, count: usize) -> Option { let offset = u64::try_from(count).ok()?; + if offset > ADDRESS_SPACE_SIZE { + return None; + } + let mut addr = start.0.checked_sub(offset)?; // Jump the gap by sign extending the 47th bit. From 3e1ed63e5d2b5d5f9ec876ce3d19cc6ad651ab5e Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 1 Mar 2022 11:16:54 +0100 Subject: [PATCH 08/27] Add some more test cases --- src/addr.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/addr.rs b/src/addr.rs index 71e7ee19e..b89e96974 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -631,7 +631,7 @@ mod tests { #[test] #[cfg(feature = "step_trait")] - fn virtaddr_step() { + fn virtaddr_step_forward() { assert_eq!(Step::forward(VirtAddr(0), 0), VirtAddr(0)); assert_eq!(Step::forward(VirtAddr(0), 1), VirtAddr(1)); assert_eq!( @@ -646,7 +646,32 @@ mod tests { Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1), None ); + assert_eq!( + Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x1234_5678_9abd), + VirtAddr(0xffff_9234_5678_9abc) + ); + assert_eq!( + Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0000), + VirtAddr(0xffff_ffff_ffff_ffff) + ); + assert_eq!( + Step::forward(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_00ff), + VirtAddr(0xffff_ffff_ffff_ffff) + ); + assert_eq!( + Step::forward_checked(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_0100), + None + ); + assert_eq!( + Step::forward_checked(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0001), + None + ); + } + + #[test] + #[cfg(feature = "step_trait")] + fn virtaddr_step_backward() { assert_eq!(Step::backward(VirtAddr(0), 0), VirtAddr(0)); assert_eq!(Step::backward_checked(VirtAddr(0), 1), None); assert_eq!(Step::backward(VirtAddr(1), 1), VirtAddr(0)); @@ -658,7 +683,27 @@ mod tests { Step::backward(VirtAddr(0xffff_8000_0000_0001), 1), VirtAddr(0xffff_8000_0000_0000) ); + assert_eq!( + Step::backward(VirtAddr(0xffff_9234_5678_9abc), 0x1234_5678_9abd), + VirtAddr(0x7fff_ffff_ffff) + ); + assert_eq!( + Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0000), + VirtAddr(0) + ); + assert_eq!( + Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x7fff_ffff_ff01), + VirtAddr(0xff) + ); + assert_eq!( + Step::backward_checked(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0001), + None + ); + } + #[test] + #[cfg(feature = "step_trait")] + fn virtaddr_steps_between() { assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0)); assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1)); assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None); From e2b5d0136fa5aa1a676478279c442608114f4172 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 1 Mar 2022 11:21:26 +0100 Subject: [PATCH 09/27] Use `checked_sub` for `steps_between` implementation An overflow should not be possible since `VirtAddr` ise guarenteed to be a canoncial address, but it's better to be safe. --- src/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addr.rs b/src/addr.rs index b89e96974..e21218817 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -335,7 +335,7 @@ impl Step for VirtAddr { // Check if we jumped the gap. if end.0.get_bit(47) && !start.0.get_bit(47) { - steps -= 0xffff_0000_0000_0000; + steps = steps.checked_sub(0xffff_0000_0000_0000).unwrap(); } usize::try_from(steps).ok() From 1602cfd7b57b427c9bdb736e74184b0d95e0a5d2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 1 Mar 2022 11:24:18 +0100 Subject: [PATCH 10/27] Use `Self::new` in `Step` methods as a safeguard This ensures that we never return a non-canonical address from these methods, even if there is a bug in the address calculation. This is important because the `VirtAddr` type guarantees that all addresses are canoncial. --- src/addr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index e21218817..cfa94557a 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -354,7 +354,7 @@ impl Step for VirtAddr { addr.set_bits(47.., 0x1ffff); } - Some(Self(addr)) + Some(Self::new(addr)) } fn backward_checked(start: Self, count: usize) -> Option { @@ -370,7 +370,7 @@ impl Step for VirtAddr { addr.set_bits(47.., 0); } - Some(Self(addr)) + Some(Self::new(addr)) } } From 29094875426d415e8edd1390117f1b8f8a32ff54 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 1 Mar 2022 11:24:27 +0100 Subject: [PATCH 11/27] Fix formatting --- src/addr.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/addr.rs b/src/addr.rs index cfa94557a..54eec85d5 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -668,7 +668,6 @@ mod tests { ); } - #[test] #[cfg(feature = "step_trait")] fn virtaddr_step_backward() { From b40eac1cd6228aa151668737923acf27074b4876 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 1 Mar 2022 11:41:32 +0100 Subject: [PATCH 12/27] Fix: `VirtAddrNotValid` and `PhysAddrNotValid` should contain the whole address Not just the invalid higher bits. We made the internal fields public in #340, but fortunately we didn't release this change yet, so this fix is still non-breaking. --- src/addr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 74f677453..0c49c9d67 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -70,7 +70,7 @@ impl VirtAddr { match addr.get_bits(47..64) { 0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical 1 => Ok(VirtAddr::new_truncate(addr)), // address needs sign extension - other => Err(VirtAddrNotValid(other)), + _ => Err(VirtAddrNotValid(addr)), } } @@ -367,7 +367,7 @@ impl PhysAddr { pub fn try_new(addr: u64) -> Result { match addr.get_bits(52..64) { 0 => Ok(PhysAddr(addr)), // address is valid - other => Err(PhysAddrNotValid(other)), + _ => Err(PhysAddrNotValid(addr)), } } From b644c2c103d52e5a1a832efda0134627a5bde2ca Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 1 Mar 2022 11:42:57 +0100 Subject: [PATCH 13/27] Format addresses as hexadecimal for VirtAddr/PhysAddr error types --- src/addr.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 0c49c9d67..f2d10c9aa 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -40,9 +40,18 @@ pub struct PhysAddr(u64); /// a valid sign extension and are not null either. So automatic sign extension would have /// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid /// address calculation. -#[derive(Debug)] +/// +/// Contains the invalid address. pub struct VirtAddrNotValid(pub u64); +impl core::fmt::Debug for VirtAddrNotValid { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VirtAddrNotValid") + .field(&format_args!("{:#x}", self.0)) + .finish() + } +} + impl VirtAddr { /// Creates a new canonical virtual address. /// @@ -325,9 +334,18 @@ impl Sub for VirtAddr { /// A passed `u64` was not a valid physical address. /// /// This means that bits 52 to 64 were not all null. -#[derive(Debug)] +/// +/// Contains the invalid address. pub struct PhysAddrNotValid(pub u64); +impl core::fmt::Debug for PhysAddrNotValid { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PhysAddrNotValid") + .field(&format_args!("{:#x}", self.0)) + .finish() + } +} + impl PhysAddr { /// Creates a new physical address. /// From 9bef8f0defb5c27d10ad39b77403b776fc72ff6c Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 1 Mar 2022 12:04:52 +0100 Subject: [PATCH 14/27] fix overflow/underflow checks --- src/addr.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 54eec85d5..31a105b97 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -349,9 +349,16 @@ impl Step for VirtAddr { let mut addr = start.0.checked_add(offset)?; - // Jump the gap by sign extending the 47th bit. - if addr.get_bits(47..) == 0x1 { - addr.set_bits(47.., 0x1ffff); + match addr.get_bits(47..) { + 0x1 => { + // Jump the gap by sign extending the 47th bit. + addr.set_bits(47.., 0x1ffff); + } + 0x2 => { + // Address overflow + return None; + } + _ => {} } Some(Self::new(addr)) @@ -365,9 +372,16 @@ impl Step for VirtAddr { let mut addr = start.0.checked_sub(offset)?; - // Jump the gap by sign extending the 47th bit. - if addr.get_bits(47..) == 0x1fffe { - addr.set_bits(47.., 0); + match addr.get_bits(47..) { + 0x1fffe => { + // Jump the gap by sign extending the 47th bit. + addr.set_bits(47.., 0); + } + 0x1fffd => { + // Address underflow + return None; + } + _ => {} } Some(Self::new(addr)) From fd8f2f1dd7d1c0b8742365e6ae53f69589a088f9 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 1 Mar 2022 12:10:07 +0100 Subject: [PATCH 15/27] fix warning --- src/addr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/addr.rs b/src/addr.rs index 31a105b97..d5d9a2da3 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -11,6 +11,7 @@ use crate::structures::paging::page_table::PageTableLevel; use crate::structures::paging::{PageOffset, PageTableIndex}; use bit_field::BitField; +#[cfg(feature = "step_trait")] const ADDRESS_SPACE_SIZE: u64 = 0x1_0000_0000_0000; /// A canonical 64-bit virtual memory address. From efd7f00b3362362a1c882340cabad192485ad372 Mon Sep 17 00:00:00 2001 From: Chris Drzewiecki Date: Fri, 18 Mar 2022 16:10:31 -0600 Subject: [PATCH 16/27] Fixed overflow bug in PageRangeInclusive --- src/structures/paging/page.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 9a538fa0f..cfbfdb7d3 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -380,7 +380,16 @@ impl Iterator for PageRangeInclusive { fn next(&mut self) -> Option { if self.start <= self.end { let page = self.start; - self.start += 1; + + // If the end of the inclusive range is the maximum page possible for size S, + // incrementing start until it is greater than the end will cause an integer overflow. + // So instead, in that case we decrement end rather than incrementing start. + let max_page_addr = VirtAddr::new(u64::MAX) - (S::SIZE - 1); + if self.start.start_address() < max_page_addr { + self.start += 1; + } else { + self.end -= 1; + } Some(page) } else { None From 6c1d77935921e527c36d9baf5cd2031b26a37806 Mon Sep 17 00:00:00 2001 From: Chris Drzewiecki Date: Fri, 18 Mar 2022 16:40:37 -0600 Subject: [PATCH 17/27] Added test to cover ranges ending in the max page --- src/structures/paging/page.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index cfbfdb7d3..b5510ddf0 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -447,4 +447,23 @@ mod tests { } assert_eq!(range_inclusive.next(), None); } + + #[test] + pub fn test_max_page_overflow() { + let page_size = Size4KiB::SIZE; + let number = 1000; + + let start_addr = VirtAddr::new(u64::MAX).align_down(page_size) - number * page_size; + let start: Page = Page::containing_address(start_addr); + let end = start + number; + + let mut range_inclusive = Page::range_inclusive(start, end); + for i in 0..=number { + assert_eq!( + range_inclusive.next(), + Some(Page::containing_address(start_addr + page_size * i)) + ); + } + assert_eq!(range_inclusive.next(), None); + } } From d75d170e8aa83bc27378447bd0e12faa57d6afe1 Mon Sep 17 00:00:00 2001 From: Chris Drzewiecki Date: Fri, 18 Mar 2022 17:19:37 -0600 Subject: [PATCH 18/27] Updated name of PageRangeInclusive overflow test --- src/structures/paging/page.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index b5510ddf0..3d84e2962 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -449,7 +449,7 @@ mod tests { } #[test] - pub fn test_max_page_overflow() { + pub fn test_page_range_inclusive_overflow() { let page_size = Size4KiB::SIZE; let number = 1000; From 34d0615f59397e0a7efed1006544f9ad78ca1de1 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 14 Mar 2022 03:03:20 +0200 Subject: [PATCH 19/27] feat: support for IA32_U_CET and IA32_S_CET Add support for IA32_U_CET and IA32_S_CET, which are used for Control flow Execution Technology (CET) configuration. Signed-off-by: Jarkko Sakkinen --- src/registers/model_specific.rs | 113 ++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index 4f55ece89..495901567 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -55,6 +55,14 @@ pub struct LStar; #[derive(Debug)] pub struct SFMask; +/// IA32_U_CET: user mode CET configuration +#[derive(Debug)] +pub struct UCet; + +/// IA32_S_CET: supervisor mode CET configuration +#[derive(Debug)] +pub struct SCet; + impl Efer { /// The underlying model specific register. pub const MSR: Msr = Msr(0xC000_0080); @@ -90,6 +98,16 @@ impl SFMask { pub const MSR: Msr = Msr(0xC000_0084); } +impl UCet { + /// The underlying model specific register. + pub const MSR: Msr = Msr(0x6A0); +} + +impl SCet { + /// The underlying model specific register. + pub const MSR: Msr = Msr(0x6A2); +} + bitflags! { /// Flags of the Extended Feature Enable Register. pub struct EferFlags: u64 { @@ -112,12 +130,37 @@ bitflags! { } } +bitflags! { + /// Flags stored in IA32_U_CET and IA32_S_CET (Table-2-2 in Intel SDM Volume + /// 4). The Intel SDM-equivalent names are described in parentheses. + pub struct CetFlags: u64 { + /// Enable shadow stack (SH_STK_EN) + const SS_ENABLE = 1 << 0; + /// Enable WRSS{D,Q}W instructions (WR_SHTK_EN) + const SS_WRITE_ENABLE = 1 << 1; + /// Enable indirect branch tracking (ENDBR_EN) + const IBT_ENABLE = 1 << 2; + /// Enable legacy treatment for indirect branch tracking (LEG_IW_EN) + const IBT_LEGACY_ENABLE = 1 << 3; + /// Enable no-track opcode prefix for indirect branch tracking (NO_TRACK_EN) + const IBT_NO_TRACK_ENABLE = 1 << 4; + /// Disable suppression of CET on legacy compatibility (SUPPRESS_DIS) + const IBT_LEGACY_SUPPRESS_ENABLE = 1 << 5; + /// Enable suppression of indirect branch tracking (SUPPRESS) + const IBT_SUPPRESS_ENABLE = 1 << 10; + /// Is IBT waiting for a branch to return? (read-only, TRACKER) + const IBT_TRACKED = 1 << 11; + } +} + #[cfg(feature = "instructions")] mod x86_64 { use super::*; use crate::addr::VirtAddr; use crate::registers::rflags::RFlags; use crate::structures::gdt::SegmentSelector; + use crate::structures::paging::Page; + use crate::structures::paging::Size4KiB; use crate::PrivilegeLevel; use bit_field::BitField; use core::convert::TryInto; @@ -445,4 +488,74 @@ mod x86_64 { unsafe { msr.write(value.bits()) }; } } + + impl UCet { + /// Read the raw IA32_U_CET. + #[inline] + fn read_raw() -> u64 { + unsafe { Self::MSR.read() } + } + + /// Write the raw IA32_U_CET. + #[inline] + fn write_raw(value: u64) { + let mut msr = Self::MSR; + unsafe { + msr.write(value); + } + } + + /// Read IA32_U_CET. Returns a tuple of the flags and the address to the legacy code page bitmap. + #[inline] + pub fn read() -> (CetFlags, Page) { + let value = Self::read_raw(); + let cet_flags = CetFlags::from_bits_truncate(value); + let legacy_bitmap = + Page::from_start_address(VirtAddr::new(value & !(Page::::SIZE - 1))) + .unwrap(); + + (cet_flags, legacy_bitmap) + } + + /// Write IA32_U_CET. + #[inline] + pub fn write(flags: CetFlags, legacy_bitmap: Page) { + Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64()); + } + } + + impl SCet { + /// Read the raw IA32_S_CET. + #[inline] + fn read_raw() -> u64 { + unsafe { Self::MSR.read() } + } + + /// Write the raw IA32_S_CET. + #[inline] + fn write_raw(value: u64) { + let mut msr = Self::MSR; + unsafe { + msr.write(value); + } + } + + /// Read IA32_S_CET. Returns a tuple of the flags and the address to the legacy code page bitmap. + #[inline] + pub fn read() -> (CetFlags, Page) { + let value = Self::read_raw(); + let cet_flags = CetFlags::from_bits_truncate(value); + let legacy_bitmap = + Page::from_start_address(VirtAddr::new(value & !(Page::::SIZE - 1))) + .unwrap(); + + (cet_flags, legacy_bitmap) + } + + /// Write IA32_S_CET. + #[inline] + pub fn write(flags: CetFlags, legacy_bitmap: Page) { + Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64()); + } + } } From e6ff36d2a3901e61541e2116fb8ce4c81f824181 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 24 Mar 2022 01:02:22 -0700 Subject: [PATCH 20/27] const_fn: Remove stablized features Both `const_fn_fn_ptr_basics` and `const_fn_trait_bound` were stabilized in Rust relese 1.61. We can't immediately remove the `const_fn!` quite yet. 1.61 is not yet on stable, and even it were, removing them would increase our MSRV to 1.61 (which we may or may not want to do in a patch release). See also: https://github.com/rust-osdev/x86_64/issues/262#issuecomment-1077340045 Signed-off-by: Joe Richey --- src/lib.rs | 2 -- src/structures/idt.rs | 1 + src/structures/paging/frame.rs | 8 +++++++- src/structures/paging/page.rs | 9 +++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dba7edd1b..738b2c0f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,6 @@ #![cfg_attr(not(test), no_std)] #![cfg_attr(feature = "const_fn", feature(const_mut_refs))] // GDT add_entry() -#![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))] // IDT new() -#![cfg_attr(feature = "const_fn", feature(const_fn_trait_bound))] // PageSize marker trait #![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))] #![cfg_attr(feature = "step_trait", feature(step_trait))] #![cfg_attr(feature = "doc_cfg", feature(doc_cfg))] diff --git a/src/structures/idt.rs b/src/structures/idt.rs index ad57dc321..15f028eb5 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -410,6 +410,7 @@ pub struct InterruptDescriptorTable { } impl InterruptDescriptorTable { + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Creates a new IDT filled with non-present entries. #[inline] diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index d64eb6b4f..e9db6f204 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -11,7 +11,8 @@ use core::ops::{Add, AddAssign, Sub, SubAssign}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct PhysFrame { - pub(crate) start_address: PhysAddr, // TODO: remove when start_address() is const + // TODO: Make private when our minimum supported stable Rust version is 1.61 + pub(crate) start_address: PhysAddr, size: PhantomData, } @@ -29,6 +30,7 @@ impl PhysFrame { Ok(unsafe { PhysFrame::from_start_address_unchecked(address) }) } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the frame that starts at the given virtual address. /// @@ -53,6 +55,7 @@ impl PhysFrame { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the start address of the frame. #[inline] @@ -61,6 +64,7 @@ impl PhysFrame { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the size the frame (4KB, 2MB or 1GB). #[inline] @@ -69,6 +73,7 @@ impl PhysFrame { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns a range of frames, exclusive `end`. #[inline] @@ -77,6 +82,7 @@ impl PhysFrame { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns a range of frames, inclusive `end`. #[inline] diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 3d84e2962..0eb6f0e8f 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -77,6 +77,7 @@ impl Page { Ok(Page::containing_address(address)) } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the page that starts at the given virtual address. /// @@ -101,6 +102,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the start address of the page. #[inline] @@ -109,6 +111,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the size the page (4KB, 2MB or 1GB). #[inline] @@ -117,6 +120,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the level 4 page table index of this page. #[inline] @@ -125,6 +129,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the level 3 page table index of this page. #[inline] @@ -133,6 +138,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the table index of this page at the specified level. #[inline] @@ -141,6 +147,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns a range of pages, exclusive `end`. #[inline] @@ -149,6 +156,7 @@ impl Page { } } + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns a range of pages, inclusive `end`. #[inline] @@ -159,6 +167,7 @@ impl Page { } impl Page { + // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 const_fn! { /// Returns the level 2 page table index of this page. #[inline] From 180a71c3a053afbedb1c7db3427cd76b073a2adc Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 24 Mar 2022 02:35:33 -0700 Subject: [PATCH 21/27] Remove inaccurate comment about const_fn Signed-off-by: Joe Richey --- src/addr.rs | 6 ++---- src/structures/gdt.rs | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 36240c371..09ec65328 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -625,8 +625,7 @@ impl Sub for PhysAddr { /// /// Returns the greatest `x` with alignment `align` so that `x <= addr`. /// -/// Panics if the alignment is not a power of two. Without the `const_fn` -/// feature, the panic message will be "index out of bounds". +/// Panics if the alignment is not a power of two. #[inline] pub const fn align_down(addr: u64, align: u64) -> u64 { assert!(align.is_power_of_two(), "`align` must be a power of two"); @@ -637,8 +636,7 @@ pub const fn align_down(addr: u64, align: u64) -> u64 { /// /// Returns the smallest `x` with alignment `align` so that `x >= addr`. /// -/// Panics if the alignment is not a power of two. Without the `const_fn` -/// feature, the panic message will be "index out of bounds". +/// Panics if the alignment is not a power of two. #[inline] pub const fn align_up(addr: u64, align: u64) -> u64 { assert!(align.is_power_of_two(), "`align` must be a power of two"); diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 2882d2e6b..855a7d89a 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -96,8 +96,7 @@ impl GlobalDescriptorTable { const_fn! { /// Adds the given segment descriptor to the GDT, returning the segment selector. /// - /// Panics if the GDT has no free entries left. Without the `const_fn` - /// feature, the panic message will be "index out of bounds". + /// Panics if the GDT has no free entries left. #[inline] pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { let index = match entry { From 9378dd34ac3b056ffbddf7b10d60fe4ef1e8c280 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 24 Mar 2022 02:41:56 -0700 Subject: [PATCH 22/27] Remove references to deprecated external_asm feature Signed-off-by: Joe Richey --- .github/workflows/build.yml | 10 +++++----- README.md | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c75adf9a..d65f86867 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,7 +64,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: doc - args: --no-default-features --features external_asm,instructions + args: --no-default-features --features instructions if: runner.os != 'Windows' - name: "Run cargo doc without default features" @@ -83,14 +83,14 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - args: --no-default-features --features external_asm,instructions + args: --no-default-features --features instructions if: runner.os != 'Windows' - name: "Run cargo build for stable on musl" uses: actions-rs/cargo@v1 with: command: build - args: --target x86_64-unknown-linux-musl --no-default-features --features external_asm,instructions + args: --target x86_64-unknown-linux-musl --no-default-features --features instructions if: runner.os == 'Linux' - name: "Run cargo test" @@ -102,14 +102,14 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --no-default-features --features external_asm,instructions + args: --no-default-features --features instructions if: runner.os != 'Windows' - name: "Run cargo test for stable on musl" uses: actions-rs/cargo@v1 with: command: test - args: --target x86_64-unknown-linux-musl --no-default-features --features external_asm,instructions + args: --target x86_64-unknown-linux-musl --no-default-features --features instructions if: runner.os == 'Linux' - name: "Install Rustup Targets" diff --git a/README.md b/README.md index 26eadd3bd..987e31943 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ Support for x86_64 specific instructions (e.g. TLB flush), registers (e.g. contr * `nightly`: Enables features only available on nightly Rust; enabled by default. * `instructions`: Enabled by default, turns on x86\_64 specific instructions, and dependent features. Only available for x86\_64 targets. -* `external_asm`: Use this to build with non-nightly rust. Needs `default-features = false, features = ["instructions"]`. Is unsupported on Windows. ## Building with stable rust From 12fd0736adcf9e4cc4aa81f04ce61c71cf5d6af1 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 24 Mar 2022 02:38:46 -0700 Subject: [PATCH 23/27] Use rustversion to conditionally make methods const Signed-off-by: Joe Richey --- Cargo.toml | 1 + src/structures/idt.rs | 64 +++++++++--------- src/structures/paging/frame.rs | 72 +++++++++----------- src/structures/paging/page.rs | 120 ++++++++++++++------------------- 4 files changed, 114 insertions(+), 143 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 71f0d1de3..5b70a5452 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ edition = "2018" bit_field = "0.10.1" bitflags = "1.0.4" volatile = "0.4.4" +rustversion = "1.0.5" [features] default = [ "nightly", "instructions" ] diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 15f028eb5..dfc960cfd 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -410,39 +410,37 @@ pub struct InterruptDescriptorTable { } impl InterruptDescriptorTable { - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Creates a new IDT filled with non-present entries. - #[inline] - pub fn new() -> InterruptDescriptorTable { - InterruptDescriptorTable { - divide_error: Entry::missing(), - debug: Entry::missing(), - non_maskable_interrupt: Entry::missing(), - breakpoint: Entry::missing(), - overflow: Entry::missing(), - bound_range_exceeded: Entry::missing(), - invalid_opcode: Entry::missing(), - device_not_available: Entry::missing(), - double_fault: Entry::missing(), - coprocessor_segment_overrun: Entry::missing(), - invalid_tss: Entry::missing(), - segment_not_present: Entry::missing(), - stack_segment_fault: Entry::missing(), - general_protection_fault: Entry::missing(), - page_fault: Entry::missing(), - reserved_1: Entry::missing(), - x87_floating_point: Entry::missing(), - alignment_check: Entry::missing(), - machine_check: Entry::missing(), - simd_floating_point: Entry::missing(), - virtualization: Entry::missing(), - reserved_2: [Entry::missing(); 8], - vmm_communication_exception: Entry::missing(), - security_exception: Entry::missing(), - reserved_3: Entry::missing(), - interrupts: [Entry::missing(); 256 - 32], - } + /// Creates a new IDT filled with non-present entries. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn new() -> InterruptDescriptorTable { + InterruptDescriptorTable { + divide_error: Entry::missing(), + debug: Entry::missing(), + non_maskable_interrupt: Entry::missing(), + breakpoint: Entry::missing(), + overflow: Entry::missing(), + bound_range_exceeded: Entry::missing(), + invalid_opcode: Entry::missing(), + device_not_available: Entry::missing(), + double_fault: Entry::missing(), + coprocessor_segment_overrun: Entry::missing(), + invalid_tss: Entry::missing(), + segment_not_present: Entry::missing(), + stack_segment_fault: Entry::missing(), + general_protection_fault: Entry::missing(), + page_fault: Entry::missing(), + reserved_1: Entry::missing(), + x87_floating_point: Entry::missing(), + alignment_check: Entry::missing(), + machine_check: Entry::missing(), + simd_floating_point: Entry::missing(), + virtualization: Entry::missing(), + reserved_2: [Entry::missing(); 8], + vmm_communication_exception: Entry::missing(), + security_exception: Entry::missing(), + reserved_3: Entry::missing(), + interrupts: [Entry::missing(); 256 - 32], } } diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index e9db6f204..64935caee 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -30,19 +30,17 @@ impl PhysFrame { Ok(unsafe { PhysFrame::from_start_address_unchecked(address) }) } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the frame that starts at the given virtual address. - /// - /// ## Safety - /// - /// The address must be correctly aligned. - #[inline] - pub unsafe fn from_start_address_unchecked(start_address: PhysAddr) -> Self { - PhysFrame { - start_address, - size: PhantomData, - } + /// Returns the frame that starts at the given virtual address. + /// + /// ## Safety + /// + /// The address must be correctly aligned. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub unsafe fn from_start_address_unchecked(start_address: PhysAddr) -> Self { + PhysFrame { + start_address, + size: PhantomData, } } @@ -55,40 +53,32 @@ impl PhysFrame { } } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the start address of the frame. - #[inline] - pub fn start_address(self) -> PhysAddr { - self.start_address - } + /// Returns the start address of the frame. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn start_address(self) -> PhysAddr { + self.start_address } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the size the frame (4KB, 2MB or 1GB). - #[inline] - pub fn size(self) -> u64 { - S::SIZE - } + /// Returns the size the frame (4KB, 2MB or 1GB). + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn size(self) -> u64 { + S::SIZE } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns a range of frames, exclusive `end`. - #[inline] - pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange { - PhysFrameRange { start, end } - } + /// Returns a range of frames, exclusive `end`. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn range(start: PhysFrame, end: PhysFrame) -> PhysFrameRange { + PhysFrameRange { start, end } } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns a range of frames, inclusive `end`. - #[inline] - pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive { - PhysFrameRangeInclusive { start, end } - } + /// Returns a range of frames, inclusive `end`. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn range_inclusive(start: PhysFrame, end: PhysFrame) -> PhysFrameRangeInclusive { + PhysFrameRangeInclusive { start, end } } } diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 0eb6f0e8f..3e2878bfe 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -77,19 +77,17 @@ impl Page { Ok(Page::containing_address(address)) } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the page that starts at the given virtual address. - /// - /// ## Safety - /// - /// The address must be correctly aligned. - #[inline] - pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self { - Page { - start_address, - size: PhantomData, - } + /// Returns the page that starts at the given virtual address. + /// + /// ## Safety + /// + /// The address must be correctly aligned. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self { + Page { + start_address, + size: PhantomData, } } @@ -102,78 +100,62 @@ impl Page { } } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the start address of the page. - #[inline] - pub fn start_address(self) -> VirtAddr { - self.start_address - } + /// Returns the start address of the page. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn start_address(self) -> VirtAddr { + self.start_address } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the size the page (4KB, 2MB or 1GB). - #[inline] - pub fn size(self) -> u64 { - S::SIZE - } + /// Returns the size the page (4KB, 2MB or 1GB). + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn size(self) -> u64 { + S::SIZE } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the level 4 page table index of this page. - #[inline] - pub fn p4_index(self) -> PageTableIndex { - self.start_address().p4_index() - } + /// Returns the level 4 page table index of this page. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn p4_index(self) -> PageTableIndex { + self.start_address().p4_index() } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the level 3 page table index of this page. - #[inline] - pub fn p3_index(self) -> PageTableIndex { - self.start_address().p3_index() - } + /// Returns the level 3 page table index of this page. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn p3_index(self) -> PageTableIndex { + self.start_address().p3_index() } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the table index of this page at the specified level. - #[inline] - pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex { - self.start_address().page_table_index(level) - } + /// Returns the table index of this page at the specified level. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex { + self.start_address().page_table_index(level) } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns a range of pages, exclusive `end`. - #[inline] - pub fn range(start: Self, end: Self) -> PageRange { - PageRange { start, end } - } + /// Returns a range of pages, exclusive `end`. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn range(start: Self, end: Self) -> PageRange { + PageRange { start, end } } - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns a range of pages, inclusive `end`. - #[inline] - pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive { - PageRangeInclusive { start, end } - } + /// Returns a range of pages, inclusive `end`. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive { + PageRangeInclusive { start, end } } } impl Page { - // TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61 - const_fn! { - /// Returns the level 2 page table index of this page. - #[inline] - pub fn p2_index(self) -> PageTableIndex { - self.start_address().p2_index() - } + /// Returns the level 2 page table index of this page. + #[inline] + #[rustversion::attr(since(1.61), const)] + pub fn p2_index(self) -> PageTableIndex { + self.start_address().p2_index() } } From e74adfe5c0944a9c4265d4d0466619851753322a Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 24 Mar 2022 02:50:58 -0700 Subject: [PATCH 24/27] Remove const_fn macro Signed-off-by: Joe Richey --- src/lib.rs | 31 ------------------- src/structures/gdt.rs | 72 +++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 68 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 738b2c0f7..3dc74b2b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,37 +12,6 @@ pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr}; -/// Makes a function const only when `feature = "const_fn"` is enabled. -/// -/// This is needed for const functions with bounds on their generic parameters, -/// such as those in `Page` and `PhysFrame` and many more. -macro_rules! const_fn { - ( - $(#[$attr:meta])* - $sv:vis fn $($fn:tt)* - ) => { - $(#[$attr])* - #[cfg(feature = "const_fn")] - $sv const fn $($fn)* - - $(#[$attr])* - #[cfg(not(feature = "const_fn"))] - $sv fn $($fn)* - }; - ( - $(#[$attr:meta])* - $sv:vis unsafe fn $($fn:tt)* - ) => { - $(#[$attr])* - #[cfg(feature = "const_fn")] - $sv const unsafe fn $($fn)* - - $(#[$attr])* - #[cfg(not(feature = "const_fn"))] - $sv unsafe fn $($fn)* - }; -} - pub mod addr; pub mod instructions; pub mod registers; diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 855a7d89a..d6181c13e 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -93,35 +93,34 @@ impl GlobalDescriptorTable { &self.table[..self.next_free] } - const_fn! { - /// Adds the given segment descriptor to the GDT, returning the segment selector. - /// - /// Panics if the GDT has no free entries left. - #[inline] - pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { - let index = match entry { - Descriptor::UserSegment(value) => self.push(value), - Descriptor::SystemSegment(value_low, value_high) => { - let index = self.push(value_low); - self.push(value_high); - index - } - }; + /// Adds the given segment descriptor to the GDT, returning the segment selector. + /// + /// Panics if the GDT has no free entries left. + #[inline] + #[cfg_attr(feature = "const_fn", rustversion::attr(all(), const))] + pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { + let index = match entry { + Descriptor::UserSegment(value) => self.push(value), + Descriptor::SystemSegment(value_low, value_high) => { + let index = self.push(value_low); + self.push(value_high); + index + } + }; - let rpl = match entry { - Descriptor::UserSegment(value) => { - if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3) - { - PrivilegeLevel::Ring3 - } else { - PrivilegeLevel::Ring0 - } + let rpl = match entry { + Descriptor::UserSegment(value) => { + if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3) + { + PrivilegeLevel::Ring3 + } else { + PrivilegeLevel::Ring0 } - Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0, - }; + } + Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0, + }; - SegmentSelector::new(index as u16, rpl) - } + SegmentSelector::new(index as u16, rpl) } /// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the @@ -155,17 +154,16 @@ impl GlobalDescriptorTable { } } - const_fn! { - #[inline] - fn push(&mut self, value: u64) -> usize { - if self.next_free < self.table.len() { - let index = self.next_free; - self.table[index] = value; - self.next_free += 1; - index - } else { - panic!("GDT full"); - } + #[inline] + #[cfg_attr(feature = "const_fn", rustversion::attr(all(), const))] + fn push(&mut self, value: u64) -> usize { + if self.next_free < self.table.len() { + let index = self.next_free; + self.table[index] = value; + self.next_free += 1; + index + } else { + panic!("GDT full"); } } From b87ecd056021cee24324f5c5ac474f33ea6f8c05 Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Thu, 24 Mar 2022 12:44:38 -0700 Subject: [PATCH 25/27] Make `Entry::handler_addr()` a public method. --- src/structures/idt.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 15f028eb5..73c6a39e3 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -735,8 +735,9 @@ impl Entry { &mut self.options } + /// Returns the virtual address of this IDT entry's handler function as a `u64`. #[inline] - fn handler_addr(&self) -> u64 { + pub fn handler_addr(&self) -> u64 { self.pointer_low as u64 | (self.pointer_middle as u64) << 16 | (self.pointer_high as u64) << 32 From 6cb2ff78d0d499cf46b6732f5516b972210f2f60 Mon Sep 17 00:00:00 2001 From: Kevin Boos Date: Thu, 24 Mar 2022 14:09:25 -0700 Subject: [PATCH 26/27] Return a `VirtAddr` from `Entry::handler_addr()`. --- src/structures/idt.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 73c6a39e3..308e4bd8e 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -735,12 +735,13 @@ impl Entry { &mut self.options } - /// Returns the virtual address of this IDT entry's handler function as a `u64`. + /// Returns the virtual address of this IDT entry's handler function. #[inline] - pub fn handler_addr(&self) -> u64 { - self.pointer_low as u64 + pub fn handler_addr(&self) -> VirtAddr { + let addr = self.pointer_low as u64 | (self.pointer_middle as u64) << 16 - | (self.pointer_high as u64) << 32 + | (self.pointer_high as u64) << 32; + VirtAddr::new_truncate(addr) } } From e6486ea2922d388968a5ab1d664a861cfe713ce8 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 25 Mar 2022 16:35:11 -0700 Subject: [PATCH 27/27] Add comment explaining why calling new-truncate is fine Signed-off-by: Joe Richey --- src/structures/idt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 308e4bd8e..aafdc44b0 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -741,6 +741,8 @@ impl Entry { let addr = self.pointer_low as u64 | (self.pointer_middle as u64) << 16 | (self.pointer_high as u64) << 32; + // addr is a valid VirtAddr, as the pointer members are either all zero, + // or have been set by set_handler_addr (which takes a VirtAddr). VirtAddr::new_truncate(addr) } }