From d482a7bf5981737644a0b716246160d56cf20412 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 10 Nov 2022 10:59:24 -0800 Subject: [PATCH 1/5] feat(hal-x86_64): make `alloc` a feature flag (#372) Currently, some code in `hal-x86_64` depends on `liballoc`, while other code does not. This makes it difficult to use parts of the HAL crate in early boot environments without an allocator. This commit adds an "alloc" feature flag to `hal-x86_64`, which enables code that depends on `liballoc`. This commit was factored out of #371. --- hal-x86_64/Cargo.toml | 2 ++ hal-x86_64/src/cpu.rs | 1 + hal-x86_64/src/lib.rs | 7 +++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hal-x86_64/Cargo.toml b/hal-x86_64/Cargo.toml index a5489ef9..ea66edc2 100644 --- a/hal-x86_64/Cargo.toml +++ b/hal-x86_64/Cargo.toml @@ -6,7 +6,9 @@ edition = "2018" license = "MIT" [features] +default = ["alloc"] log = ["tracing/log"] +alloc = [] [dependencies] acpi = "4.1.1" diff --git a/hal-x86_64/src/cpu.rs b/hal-x86_64/src/cpu.rs index b18b5eb8..6100c880 100644 --- a/hal-x86_64/src/cpu.rs +++ b/hal-x86_64/src/cpu.rs @@ -3,6 +3,7 @@ use mycelium_util::bits; pub mod entropy; pub mod intrinsics; +#[cfg(feature = "alloc")] pub mod local; mod msr; pub use self::msr::Msr; diff --git a/hal-x86_64/src/lib.rs b/hal-x86_64/src/lib.rs index 773fc012..011f4f9d 100644 --- a/hal-x86_64/src/lib.rs +++ b/hal-x86_64/src/lib.rs @@ -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; From 01caf12e3c811e8c4e24ffc2c542329a376d7a80 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 10 Nov 2022 11:07:51 -0800 Subject: [PATCH 2/5] feat(hal-x86_64): add `SystemSegment::boxed_tss` (#372) Currently, TSS segments can only be constructed from statics. This makes it difficult to construct a TSS dynamically when bringing up an application processor. This commit adds a new `SystemSegment::boxed_tss` constructor, which allows TSS segments to be dynamically allocated, as well as stored in a static. This was factored out of PR #371. --- hal-x86_64/src/segment.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hal-x86_64/src/segment.rs b/hal-x86_64/src/segment.rs index c17a477a..6f052949 100644 --- a/hal-x86_64/src/segment.rs +++ b/hal-x86_64/src/segment.rs @@ -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) -> 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..."); From 4e06fff967dd2f9f2f7a1be34644a76af3c227ae Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 10 Nov 2022 11:08:37 -0800 Subject: [PATCH 3/5] feat(hal-x86_64): add `Msr::ia32_efer` and `Efer` bitflags (#372) This commit adds support for the IA32_EFER model-specific register in the `hal-x86_64` crate's `cpu::msr` module. This includes a new `Efer` bitflags type representing the flags stored in the EFER register, and a `Msr::i32_efer` constructor for accessing the EFER. This is necessary for application processor bringup, and was factored out from PR #371. --- hal-x86_64/src/cpu.rs | 2 +- hal-x86_64/src/cpu/msr.rs | 89 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/hal-x86_64/src/cpu.rs b/hal-x86_64/src/cpu.rs index 6100c880..ed32c530 100644 --- a/hal-x86_64/src/cpu.rs +++ b/hal-x86_64/src/cpu.rs @@ -5,7 +5,7 @@ pub mod entropy; pub mod intrinsics; #[cfg(feature = "alloc")] pub mod local; -mod msr; +pub mod msr; pub use self::msr::Msr; #[repr(transparent)] diff --git a/hal-x86_64/src/cpu/msr.rs b/hal-x86_64/src/cpu/msr.rs index ebbaca37..5d3dce70 100644 --- a/hal-x86_64/src/cpu/msr.rs +++ b/hal-x86_64/src/cpu/msr.rs @@ -1,6 +1,9 @@ #![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). @@ -33,11 +36,44 @@ use raw_cpuid::CpuId; /// [sandpile]: https://sandpile.org/x86/msr.htm /// [msr]: https://wiki.osdev.org/MSR pub struct Msr { - num: u32, + pub(crate) num: u32, name: Option<&'static str>, _ty: PhantomData, } +bitfield! { + /// Bit flags for the Extended Feature Enable Register (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. + pub struct Efer { + /// 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. /// @@ -92,20 +128,36 @@ impl Msr { /// This register stores the base address of the local APIC memory-mapped /// configuration area. #[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` /// model-specific register. #[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` + /// model-specific register. + /// + /// Flags for the `IA32_EFER` MSR are represented by the [`Efer`] + /// type. + #[must_use] + pub const fn ia32_efer() -> Msr { + Msr { + name: Some("IA32_EFER"), + num: 0xc0000080, + _ty: PhantomData, } } } @@ -245,3 +297,28 @@ impl fmt::Display for Msr { } } } + +#[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" + ); + } +} From cf359576e62b4736a8594a5c935632a936ad17b4 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 10 Nov 2022 11:09:52 -0800 Subject: [PATCH 4/5] fix(kernel): ensure build script is rerun on changes (#372) This ensures that the build script is re-run if the hello world wasm or the target spec change. --- build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 0472e80a..3619dded 100644 --- a/build.rs +++ b/build.rs @@ -7,6 +7,9 @@ fn main() -> Result<(), Box> { // 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(()) } From 45ea1b797863e6a8d248129023345fab544d60a4 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Wed, 16 Nov 2022 10:13:18 -0800 Subject: [PATCH 5/5] docs(hal-x86_64): improve MSR documentation (#372) --- hal-x86_64/src/cpu/msr.rs | 72 +++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/hal-x86_64/src/cpu/msr.rs b/hal-x86_64/src/cpu/msr.rs index 5d3dce70..9bb3de2a 100644 --- a/hal-x86_64/src/cpu/msr.rs +++ b/hal-x86_64/src/cpu/msr.rs @@ -1,3 +1,17 @@ +//! 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::{ @@ -27,14 +41,32 @@ 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 { pub(crate) num: u32, name: Option<&'static str>, @@ -42,10 +74,14 @@ pub struct Msr { } bitfield! { - /// Bit flags for the Extended Feature Enable Register (EFER) [`Msr`]. + /// 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 { /// System Call Extensions (SCE). /// @@ -122,11 +158,14 @@ 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 const fn ia32_apic_base() -> Self { Self { @@ -136,8 +175,13 @@ impl Msr { } } - /// 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 const fn ia32_gs_base() -> Self { Self { @@ -147,11 +191,17 @@ impl Msr { } } - /// Returns a `Msr` for reading and writing to the `IA32_EFER` - /// model-specific register. + /// 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 { Msr {