Skip to content

Commit 40931f0

Browse files
committed
Merge branch 'next' into master
2 parents af70710 + 9afa8e9 commit 40931f0

29 files changed

+565
-530
lines changed

.github/workflows/build.yml

-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ jobs:
2121
rust:
2222
- nightly
2323
- 1.59
24-
- 1.57
2524
runs-on: ubuntu-latest
2625
steps:
2726
- uses: actions/checkout@v4
@@ -31,7 +30,6 @@ jobs:
3130
toolchain: ${{ matrix.rust }}
3231
override: true
3332
- name: Run cargo build for stable
34-
if: matrix.rust != 1.57
3533
uses: actions-rs/cargo@v1
3634
with:
3735
command: build
@@ -42,7 +40,6 @@ jobs:
4240
command: build
4341
args: --no-default-features
4442
- name: Run cargo doc for stable
45-
if: matrix.rust != 1.57
4643
uses: actions-rs/cargo@v1
4744
with:
4845
command: doc
@@ -53,7 +50,6 @@ jobs:
5350
command: doc
5451
args: --no-default-features
5552
- name: Run cargo test for stable
56-
if: matrix.rust != 1.57
5753
uses: actions-rs/cargo@v1
5854
with:
5955
command: test

Cargo.toml

+4-8
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ license = "MIT/Apache-2.0"
1515
name = "x86_64"
1616
readme = "README.md"
1717
repository = "https://github.com/rust-osdev/x86_64"
18-
version = "0.14.12"
18+
version = "0.15.0-beta"
1919
edition = "2018"
20-
rust-version = "1.57" # Needed to support panic! in const fns
20+
rust-version = "1.59" # Needed to support inline asm and default const generics
2121

2222
[dependencies]
2323
bit_field = "0.10.1"
@@ -28,17 +28,13 @@ rustversion = "1.0.5"
2828
[features]
2929
default = ["nightly", "instructions"]
3030
instructions = []
31-
nightly = ["const_fn", "step_trait", "abi_x86_interrupt"]
31+
nightly = [ "const_fn", "step_trait", "abi_x86_interrupt", "asm_const" ]
3232
abi_x86_interrupt = []
3333
const_fn = []
34+
asm_const = []
3435
step_trait = []
3536
doc_auto_cfg = []
3637

37-
# These features are no longer used and only there for backwards compatibility.
38-
external_asm = []
39-
inline_asm = []
40-
doc_cfg = []
41-
4238
[package.metadata.docs.rs]
4339
all-features = true
4440

Changelog.md

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

3+
# 0.15.0-beta – 2024-02-10
4+
5+
## Breaking changes
6+
7+
- [replace software_interrupt! macro with generic function](https://github.com/rust-osdev/x86_64/pull/259)
8+
- [Use SegmentSelector in InterruptStackFrame](https://github.com/rust-osdev/x86_64/pull/263)
9+
- [add `InvalidStarSegmentSelectors` error](https://github.com/rust-osdev/x86_64/pull/317)
10+
- [add `PcidTooBig` error](https://github.com/rust-osdev/x86_64/pull/316)
11+
- [implement `Index<u8>` for IDT instead of `Index<usize>`](https://github.com/rust-osdev/x86_64/pull/319)
12+
- [change `cpu_flags`'s type to `RFlags`](https://github.com/rust-osdev/x86_64/pull/324)
13+
- [fix `load_tss` and `GlobalDescriptorTable`](https://github.com/rust-osdev/x86_64/pull/323)
14+
- [add an immutable getter for the level 4 page table](https://github.com/rust-osdev/x86_64/pull/327)
15+
- [make `Cr2::read` return a result](https://github.com/rust-osdev/x86_64/pull/335)
16+
- [remove `external_asm` and `inline_asm` features](https://github.com/rust-osdev/x86_64/pull/345)
17+
- [Allow the GDT to be of any length](https://github.com/rust-osdev/x86_64/pull/360)
18+
- [Remove software_interrupt! macro](https://github.com/rust-osdev/x86_64/pull/363)
19+
- [Remove usize trait impls](https://github.com/rust-osdev/x86_64/pull/364)
20+
- [Remove deprecated functions/flags](https://github.com/rust-osdev/x86_64/pull/368)
21+
- [VirtAddr improvements](https://github.com/rust-osdev/x86_64/pull/370)
22+
- [Add structures::gdt::Entry type](https://github.com/rust-osdev/x86_64/pull/380)
23+
- [Allow GDT to be loaded with shared reference](https://github.com/rust-osdev/x86_64/pull/381)
24+
- [seal off the `PageSize` trait](https://github.com/rust-osdev/x86_64/pull/404)
25+
- [idt: Fixup Options structure and cleanup set_handler_fn](https://github.com/rust-osdev/x86_64/pull/226)
26+
27+
## Fixes
28+
29+
- [fix typo in docs](https://github.com/rust-osdev/x86_64/pull/265)
30+
- [activate `feature(asm_const)`](https://github.com/rust-osdev/x86_64/pull/320)
31+
- [gdt: Check that MAX is in range](https://github.com/rust-osdev/x86_64/pull/365)
32+
333
# 0.14.12 – 2023-02-09
434

535
## New Features

README.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ Support for x86_64 specific instructions (e.g. TLB flush), registers (e.g. contr
1212

1313
## Minimum Supported Rust Version (MSRV)
1414

15-
If no features are enabled (`--no-default-features`), Rust 1.57.0 is required.
15+
If no nightly features are enabled, Rust 1.59.0 is required.
16+
This can be done by either:
17+
- `--no-default-features --features instructions`
18+
- `--no-default-features`
1619

17-
If only the `instructions` feature is enabled (`--no-default-features --features instructions`), Rust 1.59.0 is required.
18-
19-
If the `nightly` feature or any of its sub-features is enabled, a recent nightly is required.
20+
If the `nightly` feature or any of its sub-features is enabled (which is the
21+
default), a recent nightly is required.
2022

2123
## Other OS development crates
2224

@@ -37,4 +39,4 @@ useful crates in this space include:
3739
[`read_volatile`](https://doc.rust-lang.org/std/ptr/fn.read_volatile.html) and
3840
[`write_volatile`](https://doc.rust-lang.org/std/ptr/fn.write_volatile.html)
3941
- Makes it easier to program [MMIO](https://en.wikipedia.org/wiki/Memory-mapped_I/O) interfaces and devices.
40-
- Works on any Rust target.
42+
- Works on any Rust target.

src/addr.rs

+26-94
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const ADDRESS_SPACE_SIZE: u64 = 0x1_0000_0000_0000;
2020
/// between `u64` and `usize`.
2121
///
2222
/// On `x86_64`, only the 48 lower bits of a virtual address can be used. The top 16 bits need
23-
/// to be copies of bit 47, i.e. the most significant bit. Addresses that fulfil this criterium
23+
/// to be copies of bit 47, i.e. the most significant bit. Addresses that fulfil this criterion
2424
/// are called “canonical”. This type guarantees that it always represents a canonical address.
2525
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2626
#[repr(transparent)]
@@ -60,39 +60,43 @@ impl core::fmt::Debug for VirtAddrNotValid {
6060
impl VirtAddr {
6161
/// Creates a new canonical virtual address.
6262
///
63-
/// This function performs sign extension of bit 47 to make the address canonical.
63+
/// The provided address should already be canonical. If you want to check
64+
/// whether an address is canonical, use [`try_new`](Self::try_new).
6465
///
6566
/// ## Panics
6667
///
67-
/// This function panics if the bits in the range 48 to 64 contain data (i.e. are not null and no sign extension).
68+
/// This function panics if the bits in the range 48 to 64 are invalid
69+
/// (i.e. are not a proper sign extension of bit 47).
6870
#[inline]
69-
pub fn new(addr: u64) -> VirtAddr {
70-
Self::try_new(addr).expect(
71-
"address passed to VirtAddr::new must not contain any data \
72-
in bits 48 to 64",
73-
)
71+
pub const fn new(addr: u64) -> VirtAddr {
72+
// TODO: Replace with .ok().expect(msg) when that works on stable.
73+
match Self::try_new(addr) {
74+
Ok(v) => v,
75+
Err(_) => panic!("virtual address must be sign extended in bits 48 to 64"),
76+
}
7477
}
7578

7679
/// Tries to create a new canonical virtual address.
7780
///
78-
/// This function tries to performs sign
79-
/// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are
80-
/// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error
81-
/// is returned.
82-
#[inline]
83-
pub fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
84-
match addr.get_bits(47..64) {
85-
0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical
86-
1 => Ok(VirtAddr::new_truncate(addr)), // address needs sign extension
87-
_ => Err(VirtAddrNotValid(addr)),
81+
/// This function checks wether the given address is canonical
82+
/// and returns an error otherwise. An address is canonical
83+
/// if bits 48 to 64 are a correct sign
84+
/// extension (i.e. copies of bit 47).
85+
#[inline]
86+
pub const fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
87+
let v = Self::new_truncate(addr);
88+
if v.0 == addr {
89+
Ok(v)
90+
} else {
91+
Err(VirtAddrNotValid(addr))
8892
}
8993
}
9094

9195
/// Creates a new canonical virtual address, throwing out bits 48..64.
9296
///
93-
/// This function performs sign extension of bit 47 to make the address canonical, so
94-
/// bits 48 to 64 are overwritten. If you want to check that these bits contain no data,
95-
/// use `new` or `try_new`.
97+
/// This function performs sign extension of bit 47 to make the address
98+
/// canonical, overwriting bits 48 to 64. If you want to check whether an
99+
/// address is canonical, use [`new`](Self::new) or [`try_new`](Self::try_new).
96100
#[inline]
97101
pub const fn new_truncate(addr: u64) -> VirtAddr {
98102
// By doing the right shift as a signed operation (on a i64), it will
@@ -123,11 +127,7 @@ impl VirtAddr {
123127
}
124128

125129
/// Creates a virtual address from the given pointer
126-
// cfg(target_pointer_width = "32") is only here for backwards
127-
// compatibility: Earlier versions of this crate did not have any `cfg()`
128-
// on this function. At least for 32- and 64-bit we know the `as u64` cast
129-
// doesn't truncate.
130-
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
130+
#[cfg(target_pointer_width = "64")]
131131
#[inline]
132132
pub fn from_ptr<T: ?Sized>(ptr: *const T) -> Self {
133133
Self::new(ptr as *const () as u64)
@@ -320,23 +320,6 @@ impl AddAssign<u64> for VirtAddr {
320320
}
321321
}
322322

323-
#[cfg(target_pointer_width = "64")]
324-
impl Add<usize> for VirtAddr {
325-
type Output = Self;
326-
#[inline]
327-
fn add(self, rhs: usize) -> Self::Output {
328-
self + rhs as u64
329-
}
330-
}
331-
332-
#[cfg(target_pointer_width = "64")]
333-
impl AddAssign<usize> for VirtAddr {
334-
#[inline]
335-
fn add_assign(&mut self, rhs: usize) {
336-
self.add_assign(rhs as u64)
337-
}
338-
}
339-
340323
impl Sub<u64> for VirtAddr {
341324
type Output = Self;
342325
#[inline]
@@ -352,23 +335,6 @@ impl SubAssign<u64> for VirtAddr {
352335
}
353336
}
354337

355-
#[cfg(target_pointer_width = "64")]
356-
impl Sub<usize> for VirtAddr {
357-
type Output = Self;
358-
#[inline]
359-
fn sub(self, rhs: usize) -> Self::Output {
360-
self - rhs as u64
361-
}
362-
}
363-
364-
#[cfg(target_pointer_width = "64")]
365-
impl SubAssign<usize> for VirtAddr {
366-
#[inline]
367-
fn sub_assign(&mut self, rhs: usize) {
368-
self.sub_assign(rhs as u64)
369-
}
370-
}
371-
372338
impl Sub<VirtAddr> for VirtAddr {
373339
type Output = u64;
374340
#[inline]
@@ -583,23 +549,6 @@ impl AddAssign<u64> for PhysAddr {
583549
}
584550
}
585551

586-
#[cfg(target_pointer_width = "64")]
587-
impl Add<usize> for PhysAddr {
588-
type Output = Self;
589-
#[inline]
590-
fn add(self, rhs: usize) -> Self::Output {
591-
self + rhs as u64
592-
}
593-
}
594-
595-
#[cfg(target_pointer_width = "64")]
596-
impl AddAssign<usize> for PhysAddr {
597-
#[inline]
598-
fn add_assign(&mut self, rhs: usize) {
599-
self.add_assign(rhs as u64)
600-
}
601-
}
602-
603552
impl Sub<u64> for PhysAddr {
604553
type Output = Self;
605554
#[inline]
@@ -615,23 +564,6 @@ impl SubAssign<u64> for PhysAddr {
615564
}
616565
}
617566

618-
#[cfg(target_pointer_width = "64")]
619-
impl Sub<usize> for PhysAddr {
620-
type Output = Self;
621-
#[inline]
622-
fn sub(self, rhs: usize) -> Self::Output {
623-
self - rhs as u64
624-
}
625-
}
626-
627-
#[cfg(target_pointer_width = "64")]
628-
impl SubAssign<usize> for PhysAddr {
629-
#[inline]
630-
fn sub_assign(&mut self, rhs: usize) {
631-
self.sub_assign(rhs as u64)
632-
}
633-
}
634-
635567
impl Sub<PhysAddr> for PhysAddr {
636568
type Output = u64;
637569
#[inline]

src/instructions/interrupts.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,19 @@ pub fn int3() {
139139

140140
/// Generate a software interrupt by invoking the `int` instruction.
141141
///
142-
/// This currently needs to be a macro because the `int` argument needs to be an
143-
/// immediate. This macro will be replaced by a generic function when support for
144-
/// const generics is implemented in Rust.
145-
#[macro_export]
146-
macro_rules! software_interrupt {
147-
($x:expr) => {{
148-
asm!("int {id}", id = const $x, options(nomem, nostack));
149-
}};
142+
/// ## Safety
143+
///
144+
/// Invoking an arbitrary interrupt is unsafe. It can cause your system to
145+
/// crash if you invoke a double-fault (#8) or machine-check (#18) exception.
146+
/// It can also cause memory/register corruption depending on the interrupt
147+
/// implementation (if it expects values/pointers to be passed in registers).
148+
#[cfg(feature = "asm_const")]
149+
#[cfg_attr(
150+
feature = "doc_cfg",
151+
doc(cfg(any(feature = "nightly", feature = "asm_const")))
152+
)]
153+
pub unsafe fn software_interrupt<const NUM: u8>() {
154+
unsafe {
155+
asm!("int {num}", num = const NUM, options(nomem, nostack));
156+
}
150157
}

0 commit comments

Comments
 (0)