Skip to content

Commit

Permalink
Merge branch 'rust-osdev:master' into enhancement/expose-cr3-write-raw
Browse files Browse the repository at this point in the history
  • Loading branch information
Freax13 committed Jan 14, 2024
2 parents c3eaa09 + 451ca2e commit 83de2f3
Show file tree
Hide file tree
Showing 21 changed files with 700 additions and 96 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
ignore:
- dependency-name: "*"
update-types:
["version-update:semver-minor", "version-update:semver-patch"]
14 changes: 7 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- 1.57
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand Down Expand Up @@ -76,7 +76,7 @@ jobs:
timeout-minutes: 15

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand Down Expand Up @@ -140,7 +140,7 @@ jobs:

steps:
- name: "Checkout Repository"
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Cache binaries
id: cache-bin
Expand Down Expand Up @@ -197,7 +197,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
Expand All @@ -214,7 +214,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
Expand All @@ -229,11 +229,11 @@ jobs:
name: Semver Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
with:
shared-key: "semver-checks"
cache-targets: false
- run: cargo install cargo-semver-checks --locked
- name: Check semver
run: cargo semver-checks check-release
run: cargo +stable semver-checks check-release
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@v3
uses: actions/checkout@v4

# TODO: Remove when Python 3.11 is the default on the Gihtub Actions image
- name: "Install Python 3.11"
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ license = "MIT/Apache-2.0"
name = "x86_64"
readme = "README.md"
repository = "https://github.com/rust-osdev/x86_64"
version = "0.14.10"
version = "0.14.11"
edition = "2018"
rust-version = "1.57" # Needed to support panic! in const fns

[dependencies]
bit_field = "0.10.1"
bitflags = "1.3.2"
bitflags = "2.3.2"
volatile = "0.4.4"
rustversion = "1.0.5"

Expand Down
35 changes: 34 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# Unreleased

## New Features

- [Add `HandlerFuncType` trait](https://github.com/rust-osdev/x86_64/pull/439)

# 0.14.11 – 2022-09-15

## New Features

- [Add missing IDT entries #CP and #HV`](https://github.com/rust-osdev/x86_64/pull/387)
- [Adding next_higher_level to PageLevelIndex](https://github.com/rust-osdev/x86_64/pull/400)
- [Adding `is_empty` to PageTable](https://github.com/rust-osdev/x86_64/pull/399)
- [Add `Descriptor::tss_segment_unchecked`](https://github.com/rust-osdev/x86_64/pull/428)
- [Add the `iretq` function to the `InterruptStackFrameValue` struct.](https://github.com/rust-osdev/x86_64/pull/431)
- [add `flush_broadcast` and `tlbsync` functions](https://github.com/rust-osdev/x86_64/pull/403)

## Fixes

- [Change Star::write() to use checked subtractions](https://github.com/rust-osdev/x86_64/pull/422)
- [add workaround for recursive page tables with recursive index 511](https://github.com/rust-osdev/x86_64/pull/425)
- [Fix off-by-one in documentation](https://github.com/rust-osdev/x86_64/pull/427)
- [Fix misc doc typos](https://github.com/rust-osdev/x86_64/pull/432)
- [add compiler fences to enable and disable](https://github.com/rust-osdev/x86_64/pull/436)

## Other Improvements

- [set repr to transparent for various types](https://github.com/rust-osdev/x86_64/pull/402)
- [Remove unused `doc_cfg` feature](https://github.com/rust-osdev/x86_64/pull/408)
- [Enable `doc_auto_cfg` on `docs.rs` builds](https://github.com/rust-osdev/x86_64/pull/407)
- [Add Descriptor::dpl const method and use it in GDT construction](https://github.com/rust-osdev/x86_64/pull/410)
- [Bump bitflags to 2.3.2](https://github.com/rust-osdev/x86_64/pull/426)
- [Add `inline` attribute to segment functions](https://github.com/rust-osdev/x86_64/pull/430)


# 0.14.10 – 2022-07-10

## New Features
Expand Down Expand Up @@ -33,7 +66,7 @@
- This trait is only available on nightly.
- Gated behind `step_trait` feature flag
- Add `UCet` and `SCet` registers ([#349](https://github.com/rust-osdev/x86_64/pull/349))
- Use [`rustversion`](https://crates.io/crates/rustversion) to mark certian functions `const fn` on Rust 1.61 ([#353](https://github.com/rust-osdev/x86_64/pull/353))
- Use [`rustversion`](https://crates.io/crates/rustversion) to mark certain functions `const fn` on Rust 1.61 ([#353](https://github.com/rust-osdev/x86_64/pull/353))
- `Entry::handler_addr()` is now public ([#354](https://github.com/rust-osdev/x86_64/pull/354))
- Increase packed structure alignment ([#362](https://github.com/rust-osdev/x86_64/pull/362))
- Make more address methods `const fn` ([#369](https://github.com/rust-osdev/x86_64/pull/369))
Expand Down
79 changes: 47 additions & 32 deletions src/addr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Physical and virtual addresses manipulation

#[cfg(feature = "step_trait")]
use core::convert::TryFrom;
use core::fmt;
#[cfg(feature = "step_trait")]
Expand All @@ -11,7 +10,6 @@ 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;

Check warning on line 13 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (nightly)

constant `ADDRESS_SPACE_SIZE` is never used

Check warning on line 13 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (nightly)

constant `ADDRESS_SPACE_SIZE` is never used

Check warning on line 13 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.59)

constant is never used: `ADDRESS_SPACE_SIZE`

Check warning on line 13 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.59)

constant is never used: `ADDRESS_SPACE_SIZE`

Check warning on line 13 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.57)

constant is never used: `ADDRESS_SPACE_SIZE`

Check warning on line 13 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.57)

constant is never used: `ADDRESS_SPACE_SIZE`

/// A canonical 64-bit virtual memory address.
Expand Down Expand Up @@ -131,8 +129,8 @@ impl VirtAddr {
// doesn't truncate.
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
#[inline]
pub fn from_ptr<T>(ptr: *const T) -> Self {
Self::new(ptr as u64)
pub fn from_ptr<T: ?Sized>(ptr: *const T) -> Self {
Self::new(ptr as *const () as u64)
}

/// Converts the address to a raw pointer.
Expand Down Expand Up @@ -226,6 +224,42 @@ impl VirtAddr {
pub const fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
PageTableIndex::new_truncate((self.0 >> 12 >> ((level as u8 - 1) * 9)) as u16)
}

// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> Option<usize> {

Check warning on line 229 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (nightly)

associated functions `steps_between_impl` and `forward_checked_impl` are never used

Check warning on line 229 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (nightly)

associated functions `steps_between_impl` and `forward_checked_impl` are never used

Check warning on line 229 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.59)

associated function is never used: `steps_between_impl`

Check warning on line 229 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.59)

associated function is never used: `steps_between_impl`

Check warning on line 229 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.57)

associated function is never used: `steps_between_impl`

Check warning on line 229 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.57)

associated function is never used: `steps_between_impl`
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 = steps.checked_sub(0xffff_0000_0000_0000).unwrap();
}

usize::try_from(steps).ok()
}

// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option<Self> {

Check warning on line 241 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.59)

associated function is never used: `forward_checked_impl`

Check warning on line 241 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.59)

associated function is never used: `forward_checked_impl`

Check warning on line 241 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.57)

associated function is never used: `forward_checked_impl`

Check warning on line 241 in src/addr.rs

View workflow job for this annotation

GitHub Actions / Test MSRV and Stable Features (1.57)

associated function is never used: `forward_checked_impl`
let offset = u64::try_from(count).ok()?;
if offset > ADDRESS_SPACE_SIZE {
return None;
}

let mut addr = start.0.checked_add(offset)?;

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))
}
}

impl fmt::Debug for VirtAddr {
Expand Down Expand Up @@ -346,37 +380,11 @@ impl Sub<VirtAddr> for VirtAddr {
#[cfg(feature = "step_trait")]
impl Step for VirtAddr {
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
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 = steps.checked_sub(0xffff_0000_0000_0000).unwrap();
}

usize::try_from(steps).ok()
Self::steps_between_impl(start, end)
}

fn forward_checked(start: Self, count: usize) -> Option<Self> {
let offset = u64::try_from(count).ok()?;
if offset > ADDRESS_SPACE_SIZE {
return None;
}

let mut addr = start.0.checked_add(offset)?;

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))
Self::forward_checked_impl(start, count)
}

fn backward_checked(start: Self, count: usize) -> Option<Self> {
Expand Down Expand Up @@ -836,4 +844,11 @@ mod tests {
fn test_phys_addr_align_up_overflow() {
PhysAddr::new(0x000f_ffff_ffff_ffff).align_up(2u64);
}

#[test]
fn test_from_ptr_array() {
let slice = &[1, 2, 3, 4, 5];
// Make sure that from_ptr(slice) is the address of the first element
assert_eq!(VirtAddr::from_ptr(slice), VirtAddr::from_ptr(&slice[0]));
}
}
12 changes: 8 additions & 4 deletions src/instructions/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ pub fn are_enabled() -> bool {
/// This is a wrapper around the `sti` instruction.
#[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(nomem, nostack));
asm!("sti", options(preserves_flags, nostack));
}
}

Expand All @@ -25,8 +27,10 @@ pub fn enable() {
/// This is a wrapper around the `cli` instruction.
#[inline]
pub fn disable() {
// Omit `nomem` to imitate a lock acquire. Otherwise, the compiler
// is free to move reads and writes through this asm block.
unsafe {
asm!("cli", options(nomem, nostack));
asm!("cli", options(preserves_flags, nostack));
}
}

Expand Down Expand Up @@ -109,10 +113,10 @@ where
/// On some processors, the interrupt shadow of `sti` does not apply to
/// non-maskable interrupts (NMIs). This means that an NMI can occur between
/// the `sti` and `hlt` instruction, with the result that the CPU is put to
/// sleep even though a new interrupt occured.
/// sleep even though a new interrupt occurred.
///
/// To work around this, it is recommended to check in the NMI handler if
/// the interrupt occured between `sti` and `hlt` instructions. If this is the
/// the interrupt occurred between `sti` and `hlt` instructions. If this is the
/// case, the handler should increase the instruction pointer stored in the
/// interrupt stack frame so that the `hlt` instruction is skipped.
///
Expand Down
6 changes: 6 additions & 0 deletions src/instructions/segmentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use core::arch::asm;

macro_rules! get_reg_impl {
($name:literal) => {
#[inline]
fn get_reg() -> SegmentSelector {
let segment: u16;
unsafe {
Expand All @@ -25,6 +26,7 @@ macro_rules! segment_impl {
impl Segment for $type {
get_reg_impl!($name);

#[inline]
unsafe fn set_reg(sel: SegmentSelector) {
unsafe {
asm!(concat!("mov ", $name, ", {0:x}"), in(reg) sel.0, options(nostack, preserves_flags));
Expand All @@ -38,6 +40,7 @@ macro_rules! segment64_impl {
($type:ty, $name:literal, $base:ty) => {
impl Segment64 for $type {
const BASE: Msr = <$base>::MSR;
#[inline]
fn read_base() -> VirtAddr {
unsafe {
let val: u64;
Expand All @@ -46,6 +49,7 @@ macro_rules! segment64_impl {
}
}

#[inline]
unsafe fn write_base(base: VirtAddr) {
unsafe{
asm!(concat!("wr", $name, "base {}"), in(reg) base.as_u64(), options(nostack, preserves_flags));
Expand All @@ -66,6 +70,7 @@ impl Segment for CS {
/// Note we cannot use a "far call" (`lcall`) or "far jmp" (`ljmp`) to do this because then we
/// 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.
#[inline]
unsafe fn set_reg(sel: SegmentSelector) {
unsafe {
asm!(
Expand Down Expand Up @@ -97,6 +102,7 @@ impl GS {
///
/// This function is unsafe because the caller must ensure that the
/// swap operation cannot lead to undefined behavior.
#[inline]
pub unsafe fn swap() {
unsafe {
asm!("swapgs", options(nostack, preserves_flags));
Expand Down

0 comments on commit 83de2f3

Please sign in to comment.