Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b66e100
fix(mapper): inline internal `map_to_*` functions
mkroening Jan 13, 2026
bb4fd95
Merge pull request #578 from mkroening/inline-map_to
Freax13 Jan 14, 2026
139e5d2
docs: fix typos
mkroening Jan 14, 2026
88f03e3
Merge pull request #579 from mkroening/typos
phil-opp Jan 14, 2026
2ba05ff
chore: add `typos.toml`
mkroening Jan 15, 2026
6d6ef5f
ci: add typos job
mkroening Jan 15, 2026
f574a1a
Merge pull request #580 from mkroening/typos-ci
phil-opp Jan 15, 2026
d2e56f7
docs(page): fix typos
mkroening Jan 15, 2026
2c86471
Merge pull request #582 from mkroening/page-typos
Freax13 Jan 16, 2026
918f72d
don't enable abi_x86_interrupt if not needed
Freax13 Mar 7, 2026
5351719
Merge pull request #585 from rust-osdev/fix/disable-int-feature
Freax13 Mar 7, 2026
c618de4
insert NOP after STI
Apr 27, 2026
d95f292
mention interrupt shadow in doc comment
Freax13 Apr 28, 2026
4fbf718
Merge pull request #588 from rust-osdev/fix/nop-after-sti
phil-opp Apr 28, 2026
adaea8b
implement kani::Arbitrary for VirtAddr and Page
Freax13 May 10, 2026
70add4a
test that jumping the address range gap panics
Freax13 May 10, 2026
28d2377
implement DoubleEndedIterator for PageRange/PageRangeInclusive
Freax13 May 10, 2026
797102e
prove that PageRange/PageRangeInclusive behave like Range
Freax13 May 10, 2026
fe0cb22
implement DoubleEndedIterator for PhysFrameRange/PhysFrameRangeInclusive
Freax13 May 10, 2026
b316d9d
implement size_hint for iterator
Freax13 May 10, 2026
42edcae
implement nth for PageRange/PageRangeInclusive
Freax13 May 10, 2026
3280ca2
implement nth_back for PageRange/PageRangeInclusive
Freax13 May 10, 2026
4518e3f
implement nth for PhysFrameRange/PhysFrameRangeInclusive
Freax13 May 17, 2026
2700117
implement nth_back for PhysFrameRange/PhysFrameRangeInclusive
Freax13 May 17, 2026
da9b070
fix next and next_back for PhysFrameRangeInclusive
Freax13 May 29, 2026
7c52dcd
add kani proofs for PhysFrame range iterators methods
Freax13 May 29, 2026
271e0fb
Merge pull request #589 from rust-osdev/feature/double-ended-iter
Freax13 May 29, 2026
bb42452
Bump actions/checkout from 6 to 7
dependabot[bot] Jun 22, 2026
e08dcf0
Merge pull request #590 from rust-osdev/dependabot/github_actions/act…
phil-opp Jun 29, 2026
32bd99d
add missing {forward,backward}_overflowing impls
tpdenk Jul 10, 2026
5e95d2f
Merge pull request #595 from tpdenk/master
Freax13 Jul 10, 2026
25ff43a
fix: :ambulance: Fixed the `Star` register's selector checking
zhangxuan2011 Jul 4, 2026
8cedd1a
feat: :sparkles: Added a function called `from_pfn`
zhangxuan2011 Jul 4, 2026
bbb1776
feat(paging): :sparkles: Added `from_pfn_unchecked`, `try_from_pfn`, …
zhangxuan2011 Jul 8, 2026
0f6126d
docs([aging): :memo: Updated docs
zhangxuan2011 Jul 8, 2026
6810ebb
revert(syscall): :bug: Revert to previous star writer
zhangxuan2011 Jul 8, 2026
4a52e0e
fix(paging): :bug: Fixed that the mul might cause overflow / panic
zhangxuan2011 Jul 9, 2026
3a5107f
feat(paging): :sparkles: Added new error type about invalid pfn
zhangxuan2011 Jul 9, 2026
b94acdc
perf(addr): :fire: Removed unnessary docs and code
zhangxuan2011 Jul 10, 2026
8f2866a
improve documentation
Freax13 Jul 10, 2026
8cc3adb
rename InvalidPfn to PfnNotValid
Freax13 Jul 10, 2026
4c75925
constify PhysFrame::from_pfn and PhysFrame::try_from_pfn
Freax13 Jul 10, 2026
98d498b
Merge pull request #593 from zhangxuan2011/master
Freax13 Jul 10, 2026
75ea0fe
update changelog
Freax13 Jul 11, 2026
88e5176
release 0.15.5
Freax13 Jul 11, 2026
8ad38d5
Merge pull request #596 from rust-osdev/release/0.15.5
Freax13 Jul 11, 2026
f6f553d
merge master into next
Wasabi375 Jul 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# rustup prioritizes environment variables over rust-toolchain.toml files.
RUSTUP_TOOLCHAIN: ${{ matrix.rust }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
Expand All @@ -56,7 +56,7 @@ jobs:
timeout-minutes: 15

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@nightly
with:
targets: x86_64-unknown-linux-musl, i686-unknown-linux-musl, thumbv7em-none-eabihf
Expand Down Expand Up @@ -94,7 +94,7 @@ jobs:

steps:
- name: "Checkout Repository"
uses: actions/checkout@v6
uses: actions/checkout@v7

- name: Cache binaries
id: cache-bin
Expand Down Expand Up @@ -148,7 +148,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
Expand All @@ -159,7 +159,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy
Expand All @@ -169,7 +169,7 @@ jobs:
name: Semver Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: Swatinem/rust-cache@v2
with:
shared-key: "semver-checks"
Expand All @@ -178,10 +178,17 @@ jobs:
- name: Check semver
run: cargo +stable semver-checks check-release --default-features

typos:
name: Typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: crate-ci/typos@v1.42.0

kani:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: Swatinem/rust-cache@v2
with:
shared-key: "kani"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

steps:
- name: "Checkout Repository"
uses: actions/checkout@v6
uses: actions/checkout@v7

- name: "Run release script"
run: "python scripts/ci-release.py"
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ license = "MIT/Apache-2.0"
name = "x86_64"
readme = "README.md"
repository = "https://github.com/rust-osdev/x86_64"
version = "0.15.4"
version = "0.15.5"
edition = "2018"
rust-version = "1.59" # Needed to support inline asm and default const generics

Expand Down
25 changes: 25 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,31 @@
- [add `MappedPageTable::display`](https://github.com/rust-osdev/x86_64/pull/574)
- The mappings of a `MappedPageTable` can now be displayed.

# 0.15.5 – 2026-07-11

This release is compatible with Rust nightlies starting with `nightly-2026-07-10` (this only applies when the `nightly` feature is used).

## New Features

- [implement DoubleEndedIterator for ranges + implement more iterator methods](https://github.com/rust-osdev/x86_64/pull/589)
- [feat: Added the "from_pfn" in PhysFrame](https://github.com/rust-osdev/x86_64/pull/593)

## Fixes

- [fix(instructions): allow unused_unsafe for cpuid](https://github.com/rust-osdev/x86_64/pull/575)
- [fix(mapper): inline internal map_to\_\* functions](https://github.com/rust-osdev/x86_64/pull/578)
- [docs: fix typos](https://github.com/rust-osdev/x86_64/pull/579)
- [docs(page): fix typos](https://github.com/rust-osdev/x86_64/pull/582)
- [don't enable abi_x86_interrupt if not needed](https://github.com/rust-osdev/x86_64/pull/585)
- [insert NOP after STI](https://github.com/rust-osdev/x86_64/pull/588)
- [add missing {forward,backward}\_overflowing impls](https://github.com/rust-osdev/x86_64/pull/595)

## Other Improvements

- [Bump actions/cache from 4 to 5](https://github.com/rust-osdev/x86_64/pull/573)
- [ci: add typos job](https://github.com/rust-osdev/x86_64/pull/580)
- [Bump actions/checkout from 6 to 7](https://github.com/rust-osdev/x86_64/pull/590)

# 0.15.4 – 2025-11-24

## New Features
Expand Down
102 changes: 70 additions & 32 deletions src/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl VirtAddr {

/// Tries to create a new canonical virtual address.
///
/// This function checks wether the given address is canonical
/// This function checks whether the given address is canonical
/// and returns an error otherwise. An address is canonical
/// if bits 48 to 64 are a correct sign
/// extension (i.e. copies of bit 47).
Expand Down Expand Up @@ -267,7 +267,6 @@ impl VirtAddr {
/// An implementation of steps_between that returns u64. Note that this
/// function always returns the exact bound, so it doesn't need to return a
/// lower and upper bound like steps_between does.
#[cfg(any(feature = "instructions", feature = "step_trait"))]
pub(crate) fn steps_between_u64(start: &Self, end: &Self) -> Option<u64> {
let mut steps = end.0.checked_sub(start.0)?;

Expand Down Expand Up @@ -494,6 +493,37 @@ impl Step for VirtAddr {
fn backward_checked(start: Self, count: usize) -> Option<Self> {
Self::backward_checked_u64(start, u64::try_from(count).ok()?)
}

// Kani's bundled toolchain predates these methods being added to `Step`.
// Exclude them there so the crate still compiles under `cargo kani`.
// This can be removed once Kani upgrades its bundled toolchain to nightly-2026-07-10 or later.
#[cfg(not(kani))]
#[inline]
fn forward_overflowing(start: Self, count: usize) -> (Self, bool) {
match Self::forward_checked(start, count) {
Some(next) => (next, false),
None => (start, true),
}
}

// Kani's bundled toolchain predates these methods being added to `Step`.
// Exclude them there so the crate still compiles under `cargo kani`.
// This can be removed once Kani upgrades its bundled toolchain to nightly-2026-07-10 or later.
#[cfg(not(kani))]
#[inline]
fn backward_overflowing(start: Self, count: usize) -> (Self, bool) {
match Self::backward_checked(start, count) {
Some(next) => (next, false),
None => (start, true),
}
}
}

#[cfg(kani)]
impl kani::Arbitrary for VirtAddr {
fn any() -> Self {
Self::new_truncate(kani::any())
}
}

/// A passed `u64` was not a valid physical address.
Expand All @@ -517,8 +547,9 @@ impl PhysAddr {
/// ## Panics
///
/// This function panics if a bit in the range 52 to 64 is set.
// If the `memory_encryption` feature has been enabled and an encryption bit has been
// configured, this also panics if the encryption bit is manually set in the address.
///
/// If the `memory_encryption` feature has been enabled and an encryption bit has been
/// configured, this also panics if the encryption bit is manually set in the address.
#[inline]
#[const_fn(cfg(not(feature = "memory_encryption")))]
pub const fn new(addr: u64) -> Self {
Expand Down Expand Up @@ -719,6 +750,13 @@ impl Sub<PhysAddr> for PhysAddr {
}
}

#[cfg(kani)]
impl kani::Arbitrary for PhysAddr {
fn any() -> Self {
Self::new_truncate(kani::any())
}
}

/// Align address downwards.
///
/// Returns the greatest `x` with alignment `align` so that `x <= addr`.
Expand Down Expand Up @@ -931,6 +969,26 @@ mod tests {
);
}

#[test]
#[cfg(feature = "step_trait")]
fn virtaddr_step_overflowing() {
assert_eq!(
Step::forward_overflowing(VirtAddr(0x7fff_ffff_ffff), 1),
(VirtAddr(0xffff_8000_0000_0000), false)
);
assert_eq!(
Step::backward_overflowing(VirtAddr(0xffff_8000_0000_0000), 1),
(VirtAddr(0x7fff_ffff_ffff), false)
);
assert_eq!(
Step::forward_overflowing(VirtAddr(0), 0),
(VirtAddr(0), false)
);

assert!(Step::forward_overflowing(VirtAddr(0xffff_ffff_ffff_ffff), 1).1);
assert!(Step::backward_overflowing(VirtAddr(0), 1).1);
}

#[test]
pub fn test_align_up() {
// align 1
Expand Down Expand Up @@ -1001,10 +1059,8 @@ mod proofs {
// step starting from any address.
#[kani::proof]
fn forward_base_case() {
let start_raw: u64 = kani::any();
let Ok(start) = VirtAddr::try_new(start_raw) else {
return;
};
let start = kani::any::<VirtAddr>();
let start_raw = start.as_u64();

// Adding 0 to any address should always yield the same address.
let same = Step::forward(start, 0);
Expand Down Expand Up @@ -1038,10 +1094,7 @@ mod proofs {
// same as taking one combined large step.
#[kani::proof]
fn forward_induction_step() {
let start_raw: u64 = kani::any();
let Ok(start) = VirtAddr::try_new(start_raw) else {
return;
};
let start = kani::any::<VirtAddr>();

let count1: usize = kani::any();
let count2: usize = kani::any();
Expand All @@ -1068,10 +1121,7 @@ mod proofs {
// for all inputs for which `forward_checked` succeeds.
#[kani::proof]
fn forward_implies_backward() {
let start_raw: u64 = kani::any();
let Ok(start) = VirtAddr::try_new(start_raw) else {
return;
};
let start = kani::any::<VirtAddr>();
let count: usize = kani::any();

// If `forward_checked` succeeds...
Expand All @@ -1088,10 +1138,7 @@ mod proofs {
// succeeds, `forward` succeeds as well.
#[kani::proof]
fn backward_implies_forward() {
let end_raw: u64 = kani::any();
let Ok(end) = VirtAddr::try_new(end_raw) else {
return;
};
let end = kani::any::<VirtAddr>();
let count: usize = kani::any();

// If `backward_checked` succeeds...
Expand All @@ -1113,10 +1160,7 @@ mod proofs {
// `steps_between` for all inputs for which `forward_checked` succeeds.
#[kani::proof]
fn forward_implies_steps_between() {
let start: u64 = kani::any();
let Ok(start) = VirtAddr::try_new(start) else {
return;
};
let start = kani::any::<VirtAddr>();
let count: usize = kani::any();

// If `forward_checked` succeeds...
Expand All @@ -1132,14 +1176,8 @@ mod proofs {
// succeeds, `forward` succeeds as well.
#[kani::proof]
fn steps_between_implies_forward() {
let start: u64 = kani::any();
let Ok(start) = VirtAddr::try_new(start) else {
return;
};
let end: u64 = kani::any();
let Ok(end) = VirtAddr::try_new(end) else {
return;
};
let start = kani::any::<VirtAddr>();
let end = kani::any::<VirtAddr>();

// If `steps_between` succeeds...
let Some(count) = Step::steps_between(&start, &end).1 else {
Expand Down
6 changes: 5 additions & 1 deletion src/instructions/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ pub fn are_enabled() -> bool {
/// Enable interrupts.
///
/// This is a wrapper around the `sti` instruction.
///
/// This function executes `sti; nop` to ensure that the interrupt shadow
/// caused by the `sti` instruction doesn't last beyond this function.
/// Use [`enable_and_hlt`] to execute `hlt` in `sti`'s interrupt shadow.
#[inline]
pub fn enable() {
// Omit `nomem` to imitate a lock release. Otherwise, the compiler
// is free to move reads and writes through this asm block.
unsafe {
asm!("sti", options(preserves_flags, nostack));
asm!("sti", "nop", options(preserves_flags, nostack));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/instructions/smap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::registers::rflags::{self, RFlags};

/// A helper type that provides SMAP related methods.
///
/// This type can only be instatiated if SMAP is supported by the CPU.
/// This type can only be instantiated if SMAP is supported by the CPU.
#[derive(Debug, Clone, Copy)]
pub struct Smap(());

Expand Down
8 changes: 7 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
//! and access to various system registers.

#![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))]
#![cfg_attr(
all(
any(target_arch = "x86", target_arch = "x86_64"),
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)]
Expand Down
16 changes: 12 additions & 4 deletions src/registers/model_specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ bitflags! {
}

bitflags! {
/// Flags for the Advanced Programmable Interrupt Controler Base Register.
/// Flags for the Advanced Programmable Interrupt Controller Base Register.
#[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct ApicBaseFlags: u64 {
Expand Down Expand Up @@ -499,9 +499,12 @@ mod x86_64 {
/// not valid for long mode.
///
/// # Parameters
/// - sysret: The CS selector is set to this field + 16. SS.Sel is set to
/// this field + 8. Because SYSRET always returns to CPL 3, the
/// RPL bits 1:0 should be initialized to 11b.
///
/// - sysret: For SYSRETQ (64-bit), the CS selector is set to this
/// field + 16. For SYSRET (32-bit), the CS selector is set to this
/// field. SS.Sel is set to this field + 8. Because SYSRETQ/SYSRET
/// always returns to CPL 3, the RPL bits 1:0 should be initialized
/// to 11b.
/// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to
/// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
/// 33:32 should be initialized to 00b.
Expand All @@ -522,11 +525,16 @@ mod x86_64 {
}

/// Write the Ring 0 and Ring 3 segment bases.
///
/// The remaining fields are ignored because they are
/// not valid for long mode.
///
/// This function will fail if the segment selectors are
/// not in the correct offset of each other or if the
/// segment selectors do not have correct privileges.
///
/// Note that `cs_sysret` should contain the segment to be used for
/// SYSRETQ (64-bit), not SYSRET (32-bit).
#[inline]
pub fn write(
cs_sysret: SegmentSelector,
Expand Down
Loading
Loading