Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cherry-pick self-contained changes from #371 #372

Merged
merged 5 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

// Build our helloworld.wast into binary.
let binary = wat::parse_file("src/helloworld.wast")?;
fs::write(out_dir.join("helloworld.wasm"), binary)?;
fs::write(out_dir.join("helloworld.wasm"), &binary)?;

println!("cargo:rerun-if-changed=src/helloworld.wast");
println!("cargo:rerun-if-changed=x86_64-mycelium.json");
Ok(())
}
2 changes: 2 additions & 0 deletions hal-x86_64/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ edition = "2018"
license = "MIT"

[features]
default = ["alloc"]
log = ["tracing/log"]
alloc = []

[dependencies]
acpi = "4.1.1"
Expand Down
3 changes: 2 additions & 1 deletion hal-x86_64/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use mycelium_util::bits;

pub mod entropy;
pub mod intrinsics;
#[cfg(feature = "alloc")]
pub mod local;
mod msr;
pub mod msr;
pub use self::msr::Msr;

#[repr(transparent)]
Expand Down
155 changes: 141 additions & 14 deletions hal-x86_64/src/cpu/msr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
//! x86_64 [Model-Specific Register][msr] (MSR)s.
//!
//! Model-specific registers are used to configure features of the CPU that may
//! not be available on all x86 processors, such as memory type-range,
//! sysenter/sysexit, local APIC, et cetera.
//!
//! This module contains the [`Msr`] type for accessing model-specific
//! registers. In addition, since most MSRs contain bitflags, this module also
//! contains bitflags types defining the flags that can be set in a particular
//! MSR.
//!
//! See the documentation for the [`Msr`] type for details on using MSRs.
//!
//! [msr]: https://wiki.osdev.org/MSR
#![warn(missing_docs)]
use core::{arch::asm, marker::PhantomData};
use mycelium_util::{bits::FromBits, fmt};
use mycelium_util::{
bits::{bitfield, FromBits},
fmt,
};
use raw_cpuid::CpuId;

/// An x86_64 [Model-Specific Register][msr] (MSR).
Expand All @@ -24,20 +41,75 @@ use raw_cpuid::CpuId;
/// reading/writing to the MSR.
///
/// When a typed representation of a MSR's value is available, a special
/// constructor is provided for accessing that MSR in a typed manner. Currently,
/// the following typed MSR constructors are abailable:
/// constructor is provided for accessing that MSR in a typed manner.
///
/// - [`Msr::ia32_apic_base`] for accessing the `IA32_APIC_BASE` MSR, which
/// stores the base address of the local APIC's memory-mapped configuration area.
/// # MSR Constructors
///
/// This type provides a number of constructors which construct a [`Msr`] for
/// accessing a specific model-specific register by name. The following
/// constructors are currently provided:
///
/// - [`Msr::ia32_apic_base`] for accessing the [`IA32_APIC_BASE`] MSR, which
/// stores the base address of the local APIC's memory-mapped configuration
/// area.
///
/// - [`Msr::ia32_gs_base`] for accessing the [`IA32_GS_BASE`] MSR, which stores
/// the base address of the `GS` segment.
///
/// - [`Msr::ia32_efer`] for accessing the [Extended Flags Enable Register
/// (EFER)][efer], which contains flags for enabling long mode and controlling
/// long-mode-specific features.
///
/// Flags for the `IA32_EFER` MSR are represented by the [`Efer`] type.
///
/// [sandpile]: https://sandpile.org/x86/msr.htm
/// [msr]: https://wiki.osdev.org/MSR
/// [efer]: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER
/// [`IA32_APIC_BASE`]: https://wiki.osdev.org/APIC#Local_APIC_configuration
/// [`IA32_GS_BASE`]: https://wiki.osdev.org/CPU_Registers_x86-64#FS.base.2C_GS.base
pub struct Msr<V = u64> {
num: u32,
pub(crate) num: u32,
name: Option<&'static str>,
_ty: PhantomData<fn(V)>,
}

bitfield! {
/// Bit flags for the [Extended Feature Enable Register (EFER)][efer] [`Msr`].
///
/// This MSR was added by AMD in the K6 processor, and became part of the
/// architecture in AMD64. It controls features related to entering long mode.
///
/// To access the EFER, use the [`Msr::ia32_efer`] constructor.
///
/// [efer]: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER
pub struct Efer<u64> {
/// System Call Extensions (SCE).
///
/// This enables the `SYSCALL` and `SYSRET` instructions.
pub const SYSTEM_CALL_EXTENSIONS: bool;
const _RESERVED_0 = 7;
/// Long Mode Enable (LME).
///
/// Setting this bit enables long mode.
pub const LONG_MODE_ENABLE: bool;
const _RESERVED_1 = 1;
/// Long Mode Active (LMA).
///
/// This bit is set if the processor is in long mode.
pub const LONG_MODE_ACTIVE: bool;
/// No-Execute Enable (NXE).
pub const NO_EXECUTE_ENABLE: bool;
/// Secure Virtual Machine Enable (SVME).
pub const SECURE_VM_ENABLE: bool;
/// Long Mode Segment Limit Enable (LMSLE).
pub const LONG_MODE_SEGMENT_LIMIT_ENABLE: bool;
/// Fast `FXSAVE`/`FXRSTOR` (FFXSR).
pub const FAST_FXSAVE_FXRSTOR: bool;
/// Translation Cache Extension (TCE).
pub const TRANSLATION_CACHE_EXTENSION: bool;
}
}

impl Msr {
/// Returns `true` if this processor has MSRs.
///
Expand Down Expand Up @@ -86,26 +158,56 @@ impl Msr {
.expect("CPU does not support model-specific registers (must be pre-Pentium...)")
}

/// Returns a `Msr` for reading and writing to the `IA32_APIC_BASE`
/// Returns a `Msr` for reading and writing to the [`IA32_APIC_BASE`]
/// model-specific register.
///
/// This register stores the base address of the local APIC memory-mapped
/// configuration area.
/// This register has MSR number 0x1B, and stores the base address of the
/// [local APIC] memory-mapped configuration area.
///
/// [`IA32_APIC_BASE`]: https://wiki.osdev.org/APIC#Local_APIC_configuration
/// [local APIC]: crate::interrupt::apic::LocalApic
#[must_use]
pub fn ia32_apic_base() -> Self {
pub const fn ia32_apic_base() -> Self {
Self {
name: Some("IA32_APIC_BASE"),
..Self::new(0x1b)
num: 0x1b,
_ty: PhantomData,
}
}

/// Returns a `Msr` for reading and writing to the `IA32_GS_BASE`
/// Returns a `Msr` for reading and writing to the [`IA32_GS_BASE`]
/// model-specific register.
///
/// This register has MSR number 0xC0000101, and contains the base address
/// of the `GS` segment.
///
/// [`IA32_GS_BASE`]: https://wiki.osdev.org/CPU_Registers_x86-64#FS.base.2C_GS.base
#[must_use]
pub fn ia32_gs_base() -> Self {
pub const fn ia32_gs_base() -> Self {
Self {
name: Some("IA32_GS_BASE"),
..Self::new(0xc000_0101)
num: 0xc000_0101,
_ty: PhantomData,
}
}

/// Returns a `Msr` for reading and writing to the [`IA32_EFER` (Extended
/// Flags Enable Register)][efer] MSR.
///
/// The EFER register has MSR number 0xC0000080, and contains flags for
/// enabling the `SYSCALL` and `SYSRET` instructions, and for entering and
/// exiting long mode, and for enabling features related to long mode.
///
/// Flags for the `IA32_EFER` MSR are represented by the [`Efer`]
/// type.
///
/// [efer]: https://wiki.osdev.org/CPU_Registers_x86-64#IA32_EFER
#[must_use]
pub const fn ia32_efer() -> Msr<Efer> {
Msr {
name: Some("IA32_EFER"),
num: 0xc0000080,
_ty: PhantomData,
}
}
}
Expand Down Expand Up @@ -245,3 +347,28 @@ impl<V> fmt::Display for Msr<V> {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn efer_valid() {
Efer::assert_valid();
println!("{}", Efer::new())
}

#[test]
fn efer_bitoffsets() {
assert_eq!(
Efer::LONG_MODE_ENABLE.least_significant_index(),
8,
"LONG_MODE_ENABLE LSB",
);
assert_eq!(
Efer::TRANSLATION_CACHE_EXTENSION.least_significant_index(),
15,
"TCE LSB"
);
}
}
7 changes: 3 additions & 4 deletions hal-x86_64/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
// Allow const operands in asm.
#![feature(asm_const)]
#![feature(abi_x86_interrupt)]
#![feature(doc_cfg)]
#![feature(doc_cfg, doc_auto_cfg)]
#![feature(extern_types)]
// A bunch of const fn features.
#![feature(const_mut_refs)]
// Oftentimes it's necessary to write to a value at a particular location in
// memory, and these types don't implement Copy to ensure they aren't
// inadvertantly copied.
#![allow(clippy::trivially_copy_pass_by_ref)]
// Macros generated by `tracing` often generate large amounts of code, which
// causes this lint to complain about relatively simple methods.
#![allow(clippy::cognitive_complexity)]

pub(crate) use hal_core::{PAddr, VAddr};
#[cfg(feature = "alloc")]
extern crate alloc;

pub mod control_regs;
Expand Down
5 changes: 5 additions & 0 deletions hal-x86_64/src/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,11 @@ impl SystemDescriptor {
const BASE_HIGH: bits::Pack64 = bits::Pack64::least_significant(32);
const BASE_HIGH_PAIR: Pair64 = Self::BASE_HIGH.pair_with(base::HIGH);

#[cfg(feature = "alloc")]
pub fn boxed_tss(tss: alloc::boxed::Box<task::StateSegment>) -> Self {
Self::tss(alloc::boxed::Box::leak(tss))
}

pub fn tss(tss: &'static task::StateSegment) -> Self {
let tss_addr = tss as *const _ as u64;
tracing::trace!(tss_addr = fmt::hex(tss_addr), "making TSS descriptor...");
Expand Down