x86: better cpuid interface

This commit is contained in:
Mark Poliakov 2024-10-12 20:43:16 +03:00
parent 82d1af7b89
commit 7a3acff20d
30 changed files with 737 additions and 623 deletions

13
Cargo.lock generated
View File

@ -863,6 +863,7 @@ dependencies = [
"bitflags 2.6.0",
"device-api",
"kernel-arch-interface",
"kernel-arch-x86",
"libk-mm-interface",
"log",
"static_assertions",
@ -878,6 +879,15 @@ dependencies = [
"yggdrasil-abi",
]
[[package]]
name = "kernel-arch-x86"
version = "0.1.0"
dependencies = [
"bitflags 2.6.0",
"kernel-arch-interface",
"tock-registers",
]
[[package]]
name = "kernel-arch-x86_64"
version = "0.1.0"
@ -885,6 +895,7 @@ dependencies = [
"bitflags 2.6.0",
"device-api",
"kernel-arch-interface",
"kernel-arch-x86",
"libk-mm-interface",
"memtables",
"static_assertions",
@ -2183,6 +2194,8 @@ dependencies = [
"kernel-arch",
"kernel-arch-aarch64",
"kernel-arch-i686",
"kernel-arch-interface",
"kernel-arch-x86",
"kernel-arch-x86_64",
"kernel-fs",
"libk",

View File

@ -11,6 +11,7 @@ authors = ["Mark Poliakov <mark@alnyan.me>"]
abi-lib = { path = "../lib/abi-lib" }
yggdrasil-abi = { path = "../lib/abi" }
kernel-arch-interface = { path = "arch/interface" }
device-api = { path = "lib/device-api", features = ["derive"] }
libk = { path = "libk" }
libk-util = { path = "libk/libk-util" }
@ -65,9 +66,11 @@ acpi_lib = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branc
acpi-system = { git = "https://github.com/alnyan/acpi-system.git" }
ygg_driver_nvme = { path = "driver/block/nvme" }
kernel-arch-x86_64 = { path = "arch/x86_64" }
kernel-arch-x86 = { path = "arch/x86" }
[target.'cfg(target_arch = "x86")'.dependencies]
kernel-arch-i686 = { path = "arch/i686" }
kernel-arch-x86 = { path = "arch/x86" }
[build-dependencies]
prettyplease = "0.2.15"
@ -79,6 +82,7 @@ aarch64-cpu = "9.4.0"
device-tree = { path = "lib/device-tree" }
kernel-arch-aarch64 = { path = "arch/aarch64" }
kernel-arch-i686 = { path = "arch/i686" }
kernel-arch-x86 = { path = "arch/x86" }
[features]
default = ["fb_console"]

View File

@ -9,6 +9,8 @@ kernel-arch-interface = { path = "../interface" }
libk-mm-interface = { path = "../../libk/libk-mm/interface" }
device-api = { path = "../../lib/device-api", features = ["derive"] }
kernel-arch-x86 = { path = "../x86" }
bitflags = "2.6.0"
static_assertions = "1.1.0"
tock-registers = "0.8.1"

View File

@ -4,11 +4,12 @@ use kernel_arch_interface::{
mem::{KernelTableManager, PhysicalMemoryAllocator},
task::{StackBuilder, TaskContext, TaskFrame, UserContextInfo},
};
use kernel_arch_x86::registers::CR3;
use libk_mm_interface::address::{AsPhysicalAddress, PhysicalAddress};
use tock_registers::interfaces::Writeable;
use yggdrasil_abi::{arch::SavedFrame, error::Error};
use crate::{gdt::TSS, mem::KERNEL_TABLES, registers::CR3};
use crate::{gdt::TSS, mem::KERNEL_TABLES};
#[allow(unused)]
#[repr(C)]
@ -164,7 +165,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
if dst != src {
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3);
CR3.set(self.cr3 as _);
__i686_switch_task(dst, src);
}
@ -172,14 +173,14 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
unsafe fn enter(&self) -> ! {
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3);
CR3.set(self.cr3 as _);
__i686_enter_task(self.inner.get())
}
unsafe fn switch_and_drop(&self, thread: *const ()) {
TSS.esp0 = self.tss_esp0;
CR3.set(self.cr3);
CR3.set(self.cr3 as _);
__i686_switch_and_drop(self.inner.get(), thread)
}

View File

@ -16,15 +16,18 @@ use kernel_arch_interface::{
pub mod context;
pub mod gdt;
pub mod mem;
pub mod registers;
pub use context::TaskContextImpl;
use kernel_arch_x86::cpuid::CpuFeatures;
pub use mem::{KernelTableManagerImpl, ProcessAddressSpaceImpl};
pub struct ArchitectureImpl;
#[repr(C)]
pub struct PerCpuData {}
pub struct PerCpuData {
pub available_features: CpuFeatures,
pub enabled_features: CpuFeatures,
}
static mut CPU: *mut () = null_mut();
@ -44,6 +47,7 @@ extern "C" fn idle_task(_: usize) -> ! {
impl Architecture for ArchitectureImpl {
type PerCpuData = PerCpuData;
type CpuFeatures = CpuFeatures;
unsafe fn init_local_cpu<S: Scheduler + 'static>(id: Option<u32>, data: Self::PerCpuData) {
use alloc::boxed::Box;
@ -118,4 +122,12 @@ impl Architecture for ArchitectureImpl {
}
}
}
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.available_features)
}
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.enabled_features)
}
}

View File

@ -1,156 +0,0 @@
macro_rules! impl_read {
($t:ident, $register:ty, $body:expr) => {
impl tock_registers::interfaces::Readable for $t {
type T = u32;
type R = $register;
#[inline]
fn get(&self) -> u32 {
$body
}
}
};
}
macro_rules! impl_write {
($t:ident, $register:ty, $value:ident, $body:expr) => {
impl tock_registers::interfaces::Writeable for $t {
type T = u32;
type R = $register;
#[inline]
fn set(&self, $value: u32) {
$body
}
}
};
}
macro_rules! cr_impl_read {
($t:ident, $cr:ident, $register:ty) => {
impl_read!($t, $register, {
let value: u32;
unsafe {
core::arch::asm!(
concat!("mov %", stringify!($cr), ", {0:e}"),
out(reg) value,
options(att_syntax)
);
}
value
});
};
}
macro_rules! cr_impl_write {
($t:ident, $cr:ident, $register:ty) => {
impl_write!($t, $register, value, {
unsafe {
core::arch::asm!(
concat!("mov {0:e}, %", stringify!($cr)),
in(reg) value,
options(att_syntax)
);
}
});
};
}
mod cr0 {
use tock_registers::register_bitfields;
register_bitfields! {
u32,
#[allow(missing_docs)]
pub CR0 [
PG OFFSET(31) NUMBITS(1) [],
CD OFFSET(30) NUMBITS(1) [],
NW OFFSET(29) NUMBITS(1) [],
AM OFFSET(18) NUMBITS(1) [],
WP OFFSET(16) NUMBITS(1) [],
NE OFFSET(5) NUMBITS(1) [],
ET OFFSET(4) NUMBITS(1) [],
TS OFFSET(3) NUMBITS(1) [],
EM OFFSET(2) NUMBITS(1) [],
MP OFFSET(1) NUMBITS(1) [],
PE OFFSET(0) NUMBITS(1) [],
]
}
pub struct Reg;
cr_impl_read!(Reg, cr0, CR0::Register);
cr_impl_write!(Reg, cr0, CR0::Register);
/// x86-64 control register 0
pub const CR0: Reg = Reg;
}
mod cr3 {
use tock_registers::{interfaces::ReadWriteable, register_bitfields};
register_bitfields! {
u32,
#[allow(missing_docs)]
pub CR3 [
ADDR OFFSET(12) NUMBITS(20) [],
]
}
pub struct Reg;
cr_impl_read!(Reg, cr3, CR3::Register);
cr_impl_write!(Reg, cr3, CR3::Register);
impl Reg {
pub fn set_address(&self, address: usize) {
assert_eq!(address & 0xFFF, 0);
self.modify(CR3::ADDR.val((address as u32) >> 12))
}
}
/// x86-64 control register 3
pub const CR3: Reg = Reg;
}
mod cr4 {
use tock_registers::register_bitfields;
register_bitfields! {
u32,
#[allow(missing_docs)]
pub CR4 [
/// If set, XSAVE and extended processor states are enabled
OSXSAVE OFFSET(18) NUMBITS(1) [],
/// Indicates OS support for FXSAVE and FXRSTOR instructions
OSFXSR OFFSET(9) NUMBITS(1) [],
/// Performance-Monitoring Counter enable
PCE OFFSET(8) NUMBITS(1) [],
/// If set, "page global" attribute is enabled
PGE OFFSET(7) NUMBITS(1) [],
/// Machine Check enable
MCE OFFSET(6) NUMBITS(1) [],
/// Physical Address Extension (enabled if 64-bit mode)
PAE OFFSET(5) NUMBITS(1) [],
/// Page Size Extension (should be enabled by yboot)
PSE OFFSET(4) NUMBITS(1) [],
/// Debugging extensions
DE OFFSET(3) NUMBITS(1) [],
TSD OFFSET(2) NUMBITS(1) [],
PVI OFFSET(1) NUMBITS(1) [],
VME OFFSET(0) NUMBITS(1) [],
]
}
pub struct Reg;
cr_impl_read!(Reg, cr4, CR4::Register);
cr_impl_write!(Reg, cr4, CR4::Register);
/// x86-64 control register 4
pub const CR4: Reg = Reg;
}
pub use cr0::CR0;
pub use cr3::CR3;
pub use cr4::CR4;

View File

@ -30,6 +30,10 @@ pub struct IpiQueue<A: Architecture> {
data: IrqSafeSpinlock<A, Option<IpiMessage>>,
}
pub trait CpuFeatureSet {
fn iter(&self) -> impl Iterator<Item = &'static str>;
}
impl<A: Architecture, S: Scheduler + 'static> CpuImpl<A, S> {
pub fn new(id: u32, inner: A::PerCpuData) -> Self {
Self {
@ -97,6 +101,14 @@ impl<A: Architecture, S: Scheduler + 'static> CpuImpl<A, S> {
// XXX
todo!()
}
pub fn available_features(&self) -> Option<&A::CpuFeatures> {
A::cpu_available_features(self)
}
pub fn enabled_features(&self) -> Option<&A::CpuFeatures> {
A::cpu_enabled_features(self)
}
}
impl<A: Architecture, S: Scheduler> Deref for CpuImpl<A, S> {

View File

@ -3,7 +3,7 @@
#![allow(clippy::new_without_default)]
use alloc::vec::Vec;
use cpu::IpiQueue;
use cpu::{CpuFeatureSet, CpuImpl, IpiQueue};
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use task::Scheduler;
@ -24,6 +24,7 @@ pub const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
pub trait Architecture: Sized {
type PerCpuData;
type CpuFeatures: CpuFeatureSet;
// Cpu management
@ -64,4 +65,13 @@ pub trait Architecture: Sized {
fn message_interrupt_controller() -> &'static dyn MessageInterruptController {
unimplemented!()
}
#[allow(unused)]
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
None
}
#[allow(unused)]
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
None
}
}

View File

@ -0,0 +1,13 @@
[package]
name = "kernel-arch-x86"
version = "0.1.0"
edition = "2021"
[dependencies]
kernel-arch-interface = { path = "../interface" }
bitflags = "2.6.0"
tock-registers = "0.8.1"
[lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(rust_analyzer)'] }

View File

@ -0,0 +1,253 @@
use core::ops::{BitAnd, BitOr};
use crate::registers::{CR0, CR4, XCR0};
use kernel_arch_interface::cpu::CpuFeatureSet;
use tock_registers::interfaces::ReadWriteable;
macro_rules! cpuid_features {
($vis:vis $name:ident: $ty:ty [ $($feature:ident: $bit:literal),* ]) => {
bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
$vis struct $name: $ty {
$(const $feature = 1 << $bit;)*
}
}
impl $name {
pub fn as_str(&self) -> &'static str {
match self {
$(&Self::$feature => stringify!($feature),)*
_ => "(unknown)"
}
}
}
};
}
cpuid_features! {
pub EcxFeatures: u32 [
SSE3: 0,
PCLMUL: 1,
DTES64: 2,
MONITOR: 3,
DS_CPL: 4,
VMX: 5,
SMX: 6,
EST: 7,
TM2: 8,
SSSE3: 9,
CID: 10,
SDBG: 11,
FMA: 12,
CX16: 13,
XTPR: 14,
PDCM: 15,
PCID: 17,
DCA: 18,
SSE4_1: 19,
SSE4_2: 20,
X2APIC: 21,
MOVBE: 22,
POPCNT: 23,
TSC: 24,
AES: 25,
XSAVE: 26,
OSXSAVE: 27,
AVX: 28,
F16C: 29,
RDRAND: 30,
HYPERVISOR: 31
]
}
cpuid_features! {
pub EdxFeatures: u32 [
FPU: 0,
VME: 1,
DE: 2,
PSE: 3,
TSC: 4,
MSR: 5,
PAE: 6,
MCE: 7,
CX8: 8,
APIC: 9,
SEP: 11,
MTRR: 12,
PGE: 13,
MCA: 14,
CMOV: 15,
PAT: 16,
PSE36: 17,
PSN: 18,
CLFLUSH: 19,
DS: 21,
ACPI: 22,
MMX: 23,
FXSR: 24,
SSE: 25,
SSE2: 26,
SS: 27,
HTT: 28,
TM: 29,
IA64: 30,
PBE: 31
]
}
#[derive(Clone, Copy, Debug)]
pub struct CpuFeatures {
pub ecx: EcxFeatures,
pub edx: EdxFeatures,
}
impl CpuFeatures {
pub const fn empty() -> Self {
Self {
ecx: EcxFeatures::empty(),
edx: EdxFeatures::empty(),
}
}
pub fn contains_all(&self, features: &Self) -> bool {
self.ecx.contains(features.ecx) && self.edx.contains(features.edx)
}
pub fn match_all(&self, features: &Self) -> Result<(), Self> {
if self.contains_all(features) {
Ok(())
} else {
Err(Self {
ecx: features.ecx & !self.ecx,
edx: features.edx & !self.edx,
})
}
}
}
impl BitAnd<CpuFeatures> for CpuFeatures {
type Output = CpuFeatures;
fn bitand(self, rhs: CpuFeatures) -> Self::Output {
Self {
ecx: self.ecx & rhs.ecx,
edx: self.edx & rhs.edx,
}
}
}
impl BitOr<CpuFeatures> for CpuFeatures {
type Output = CpuFeatures;
fn bitor(self, rhs: CpuFeatures) -> Self::Output {
Self {
ecx: self.ecx | rhs.ecx,
edx: self.edx | rhs.edx,
}
}
}
impl CpuFeatureSet for CpuFeatures {
fn iter(&self) -> impl Iterator<Item = &'static str> {
let ecx = self.ecx.iter().map(|e| e.as_str());
let edx = self.edx.iter().map(|e| e.as_str());
core::iter::chain(ecx, edx)
}
}
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
unsafe fn raw_cpuid(eax: u32, result: &mut [u32]) {
core::arch::asm!(
r#"
push %rbx
cpuid
mov %ebx, {0:e}
pop %rbx
"#,
out(reg) result[0],
out("edx") result[1],
out("ecx") result[2],
in("eax") eax,
options(att_syntax)
);
}
#[cfg(any(target_arch = "x86", rust_analyzer))]
unsafe fn raw_cpuid(eax: u32, result: &mut [u32]) {
core::arch::asm!(
r#"
push %ebx
cpuid
mov %ebx, {0:e}
pop %ebx
"#,
out(reg) result[0],
out("edx") result[1],
out("ecx") result[2],
in("eax") eax,
options(att_syntax)
);
}
fn cpuid_features() -> (EcxFeatures, EdxFeatures) {
let mut raw = [0; 3];
unsafe {
raw_cpuid(0x1, &mut raw);
}
(
EcxFeatures::from_bits_truncate(raw[2]),
EdxFeatures::from_bits_truncate(raw[1]),
)
}
fn enable_features(ecx: EcxFeatures, edx: EdxFeatures) {
if ecx.contains(EcxFeatures::XSAVE) {
CR4.modify(CR4::OSXSAVE::SET);
}
if edx.contains(EdxFeatures::FXSR) {
CR4.modify(CR4::OSFXSR::SET);
}
if edx.contains(EdxFeatures::FPU) {
CR0.modify(CR0::EM::CLEAR);
if ecx.contains(EcxFeatures::XSAVE) {
XCR0.modify(XCR0::X87::SET);
}
}
if edx.contains(EdxFeatures::SSE) && ecx.contains(EcxFeatures::XSAVE) {
XCR0.modify(XCR0::SSE::SET);
}
if ecx.contains(EcxFeatures::AVX) {
// Must also have FPU enabled
assert!(edx.contains(EdxFeatures::FPU) && ecx.contains(EcxFeatures::XSAVE));
XCR0.modify(XCR0::AVX::SET);
}
if ecx.contains(EcxFeatures::PCID) {
CR4.modify(CR4::PCIDE::SET);
}
CR0.modify(CR0::TS::CLEAR);
}
fn read_features() -> CpuFeatures {
let (ecx, edx) = cpuid_features();
CpuFeatures { ecx, edx }
}
pub fn setup_features(
want_features: CpuFeatures,
need_features: CpuFeatures,
) -> (CpuFeatures, Result<CpuFeatures, CpuFeatures>) {
let have_features = read_features();
let will_features = have_features & (want_features | need_features);
if let Err(missing_features) = will_features.match_all(&need_features) {
return (have_features, Err(missing_features));
}
enable_features(will_features.ecx, will_features.edx);
(have_features, Ok(will_features))
}

View File

@ -0,0 +1,5 @@
#![feature(iter_chain)]
#![no_std]
pub mod cpuid;
pub mod registers;

View File

@ -1,14 +1,11 @@
//! Helper types for interfacing with x86-64 registers
#![allow(unused)]
macro_rules! impl_read {
($t:ident, $register:ty, $body:expr) => {
($t:ident, $repr:ty, $register:ty, $body:expr) => {
impl tock_registers::interfaces::Readable for $t {
type T = u64;
type T = $repr;
type R = $register;
#[inline]
fn get(&self) -> u64 {
fn get(&self) -> $repr {
$body
}
}
@ -16,22 +13,52 @@ macro_rules! impl_read {
}
macro_rules! impl_write {
($t:ident, $register:ty, $value:ident, $body:expr) => {
($t:ident, $repr:ty, $register:ty, $value:ident, $body:expr) => {
impl tock_registers::interfaces::Writeable for $t {
type T = u64;
type T = $repr;
type R = $register;
#[inline]
fn set(&self, $value: u64) {
fn set(&self, $value: $repr) {
$body
}
}
};
}
macro_rules! cr_impl_read {
($t:ident, $repr:ty, $cr:ident, $register:ty) => {
impl_read!($t, $repr, $register, {
let value: $repr;
unsafe {
core::arch::asm!(
concat!("mov %", stringify!($cr), ", {0}"),
out(reg) value,
options(att_syntax)
);
}
value
});
};
}
macro_rules! cr_impl_write {
($t:ident, $repr:ty, $cr:ident, $register:ty) => {
impl_write!($t, $repr, $register, value, {
unsafe {
core::arch::asm!(
concat!("mov {0}, %", stringify!($cr)),
in(reg) value,
options(att_syntax)
);
}
});
};
}
macro_rules! msr_impl_read {
($t:ident, $addr:expr, $register:ty) => {
impl_read!($t, $register, {
impl_read!($t, u64, $register, {
let (high, low): (u32, u32);
unsafe {
core::arch::asm!(
@ -51,7 +78,7 @@ macro_rules! msr_impl_read {
macro_rules! msr_impl_write {
($t:ident, $addr:expr, $register:ty) => {
impl_write!($t, $register, value, {
impl_write!($t, u64, $register, value, {
let low = value as u32;
let high = (value >> 32) as u32;
unsafe {
@ -69,175 +96,11 @@ macro_rules! msr_impl_write {
($t:ident, $addr:expr) => { msr_impl_write!($t, $addr, ()); };
}
macro_rules! cr_impl_read {
($t:ident, $cr:ident, $register:ty) => {
impl_read!($t, $register, {
let value: u64;
unsafe {
core::arch::asm!(
concat!("mov %", stringify!($cr), ", {}"),
out(reg) value,
options(att_syntax)
);
}
value
});
};
}
macro_rules! cr_impl_write {
($t:ident, $cr:ident, $register:ty) => {
impl_write!($t, $register, value, {
unsafe {
core::arch::asm!(
concat!("mov {}, %", stringify!($cr)),
in(reg) value,
options(att_syntax)
);
}
});
};
}
mod msr_ia32_kernel_gs_base {
const ADDR: u32 = 0xC0000102;
pub struct Reg;
msr_impl_read!(Reg, ADDR);
msr_impl_write!(Reg, ADDR);
/// IA32_KERNEL_GS_BASE model-specific register. Provides the base address for %gs-relative
/// loads/stores.
pub const MSR_IA32_KERNEL_GS_BASE: Reg = Reg;
}
mod msr_ia32_apic_base {
use tock_registers::{interfaces::Readable, register_bitfields};
register_bitfields! {
u64,
#[allow(missing_docs)]
#[doc = "IA32_APIC_BASE model-specific register"]
pub MSR_IA32_APIC_BASE [
#[doc = "Contains a virtual page number of the Local APIC base address for this processor"]
AddressPage OFFSET(12) NUMBITS(40) [],
#[doc = "If set, the APIC is enabled"]
ApicEnable OFFSET(11) NUMBITS(1) [],
#[doc = "If set, x2APIC mode is enabled"]
ExtendedEnable OFFSET(10) NUMBITS(1) [],
#[doc = "If set, this CPU is a bootstrap processor"]
BootstrapCpuCore OFFSET(8) NUMBITS(1) [],
]
}
const ADDR: u32 = 0x0000001B;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_APIC_BASE::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_APIC_BASE::Register);
impl Reg {
#[inline]
pub fn read_base(&self) -> u64 {
self.read(MSR_IA32_APIC_BASE::AddressPage) << 12
}
}
/// IA32_APIC_BASE model-specific register
pub const MSR_IA32_APIC_BASE: Reg = Reg;
}
mod msr_ia32_sfmask {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[allow(missing_docs)]
pub MSR_IA32_SFMASK [
IF OFFSET(9) NUMBITS(1) [
Masked = 1,
Unmasked = 0
],
TF OFFSET(8) NUMBITS(1) [
Masked = 1,
Unmasked = 0
]
]
}
const ADDR: u32 = 0xC0000084;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_SFMASK::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_SFMASK::Register);
/// IA32_SFMASK model-specific register
pub const MSR_IA32_SFMASK: Reg = Reg;
}
mod msr_ia32_star {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[allow(missing_docs)]
pub MSR_IA32_STAR [
SYSCALL_CS_SS OFFSET(32) NUMBITS(16) [],
SYSRET_CS_SS OFFSET(48) NUMBITS(16) [],
]
}
const ADDR: u32 = 0xC0000081;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_STAR::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_STAR::Register);
/// IA32_STAR model-specific register
pub const MSR_IA32_STAR: Reg = Reg;
}
mod msr_ia32_lstar {
const ADDR: u32 = 0xC0000082;
pub struct Reg;
msr_impl_read!(Reg, ADDR);
msr_impl_write!(Reg, ADDR);
/// IA32_LSTAR model-specific register
pub const MSR_IA32_LSTAR: Reg = Reg;
}
mod msr_ia32_efer {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[allow(missing_docs)]
pub MSR_IA32_EFER [
// If set, support for SYSCALL/SYSRET instructions is enabled
SCE OFFSET(0) NUMBITS(1) [
Enable = 1,
Disable = 0
]
]
}
const ADDR: u32 = 0xC0000080;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_EFER::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_EFER::Register);
/// IA32_EFER Extended Feature Enable model-specific Register
pub const MSR_IA32_EFER: Reg = Reg;
}
mod cr0 {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
usize,
#[allow(missing_docs)]
pub CR0 [
PG OFFSET(31) NUMBITS(1) [],
@ -256,33 +119,52 @@ mod cr0 {
pub struct Reg;
cr_impl_read!(Reg, cr0, CR0::Register);
cr_impl_write!(Reg, cr0, CR0::Register);
cr_impl_read!(Reg, usize, cr0, CR0::Register);
cr_impl_write!(Reg, usize, cr0, CR0::Register);
/// x86-64 control register 0
pub const CR0: Reg = Reg;
}
mod cr2 {
use tock_registers::register_bitfields;
register_bitfields! {
usize,
#[allow(missing_docs)]
pub CR2 [
ADDRESS OFFSET(0) NUMBITS(size_of::<usize>())
]
}
pub struct Reg;
cr_impl_read!(Reg, usize, cr2, CR2::Register);
/// x86 control register 2
pub const CR2: Reg = Reg;
}
mod cr3 {
use tock_registers::{interfaces::ReadWriteable, register_bitfields};
register_bitfields! {
u64,
usize,
#[allow(missing_docs)]
pub CR3 [
ADDR OFFSET(12) NUMBITS(40) [],
ADDR OFFSET(12) NUMBITS(20) [],
]
}
pub struct Reg;
cr_impl_read!(Reg, cr3, CR3::Register);
cr_impl_write!(Reg, cr3, CR3::Register);
cr_impl_read!(Reg, usize, cr3, CR3::Register);
cr_impl_write!(Reg, usize, cr3, CR3::Register);
impl Reg {
pub fn set_address(&self, address: usize) {
assert_eq!(address & 0xFFF, 0);
self.modify(CR3::ADDR.val((address as u64) >> 12))
self.modify(CR3::ADDR.val(address >> 12))
}
}
@ -294,11 +176,13 @@ mod cr4 {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
usize,
#[allow(missing_docs)]
pub CR4 [
/// If set, XSAVE and extended processor states are enabled
OSXSAVE OFFSET(18) NUMBITS(1) [],
/// If set, PCID is enabled
PCIDE OFFSET(17) NUMBITS(1) [],
/// Indicates OS support for FXSAVE and FXRSTOR instructions
OSFXSR OFFSET(9) NUMBITS(1) [],
/// Performance-Monitoring Counter enable
@ -321,8 +205,8 @@ mod cr4 {
pub struct Reg;
cr_impl_read!(Reg, cr4, CR4::Register);
cr_impl_write!(Reg, cr4, CR4::Register);
cr_impl_read!(Reg, usize, cr4, CR4::Register);
cr_impl_write!(Reg, usize, cr4, CR4::Register);
/// x86-64 control register 4
pub const CR4: Reg = Reg;
@ -392,45 +276,169 @@ mod xcr0 {
pub const XCR0: Reg = Reg;
}
use core::ptr::NonNull;
mod msr {
pub mod ia32_kernel_gs_base {
const ADDR: u32 = 0xC0000102;
pub struct Reg;
msr_impl_read!(Reg, ADDR);
msr_impl_write!(Reg, ADDR);
/// IA32_KERNEL_GS_BASE model-specific register. Provides the base address for %gs-relative
/// loads/stores.
pub const MSR_IA32_KERNEL_GS_BASE: Reg = Reg;
}
pub mod ia32_apic_base {
use tock_registers::{interfaces::Readable, register_bitfields};
register_bitfields! {
u64,
#[allow(missing_docs)]
#[doc = "IA32_APIC_BASE model-specific register"]
pub MSR_IA32_APIC_BASE [
#[doc = "Contains a virtual page number of the Local APIC base address for this processor"]
AddressPage OFFSET(12) NUMBITS(40) [],
#[doc = "If set, the APIC is enabled"]
ApicEnable OFFSET(11) NUMBITS(1) [],
#[doc = "If set, x2APIC mode is enabled"]
ExtendedEnable OFFSET(10) NUMBITS(1) [],
#[doc = "If set, this CPU is a bootstrap processor"]
BootstrapCpuCore OFFSET(8) NUMBITS(1) [],
]
}
const ADDR: u32 = 0x0000001B;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_APIC_BASE::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_APIC_BASE::Register);
impl Reg {
#[inline]
pub fn read_base(&self) -> u64 {
self.read(MSR_IA32_APIC_BASE::AddressPage) << 12
}
}
/// IA32_APIC_BASE model-specific register
pub const MSR_IA32_APIC_BASE: Reg = Reg;
}
pub mod ia32_sfmask {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[allow(missing_docs)]
pub MSR_IA32_SFMASK [
IF OFFSET(9) NUMBITS(1) [
Masked = 1,
Unmasked = 0
],
TF OFFSET(8) NUMBITS(1) [
Masked = 1,
Unmasked = 0
]
]
}
const ADDR: u32 = 0xC0000084;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_SFMASK::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_SFMASK::Register);
/// IA32_SFMASK model-specific register
pub const MSR_IA32_SFMASK: Reg = Reg;
}
pub mod ia32_star {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[allow(missing_docs)]
pub MSR_IA32_STAR [
SYSCALL_CS_SS OFFSET(32) NUMBITS(16) [],
SYSRET_CS_SS OFFSET(48) NUMBITS(16) [],
]
}
const ADDR: u32 = 0xC0000081;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_STAR::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_STAR::Register);
/// IA32_STAR model-specific register
pub const MSR_IA32_STAR: Reg = Reg;
}
pub mod ia32_lstar {
const ADDR: u32 = 0xC0000082;
pub struct Reg;
msr_impl_read!(Reg, ADDR);
msr_impl_write!(Reg, ADDR);
/// IA32_LSTAR model-specific register
pub const MSR_IA32_LSTAR: Reg = Reg;
}
pub mod ia32_efer {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[allow(missing_docs)]
pub MSR_IA32_EFER [
// If set, support for SYSCALL/SYSRET instructions is enabled
SCE OFFSET(0) NUMBITS(1) [
Enable = 1,
Disable = 0
]
]
}
const ADDR: u32 = 0xC0000080;
pub struct Reg;
msr_impl_read!(Reg, ADDR, MSR_IA32_EFER::Register);
msr_impl_write!(Reg, ADDR, MSR_IA32_EFER::Register);
/// IA32_EFER Extended Feature Enable model-specific Register
pub const MSR_IA32_EFER: Reg = Reg;
}
}
pub use cr0::CR0;
pub use cr2::CR2;
pub use cr3::CR3;
pub use cr4::CR4;
pub use msr_ia32_apic_base::MSR_IA32_APIC_BASE;
pub use msr_ia32_efer::MSR_IA32_EFER;
pub use msr_ia32_kernel_gs_base::MSR_IA32_KERNEL_GS_BASE;
pub use msr_ia32_lstar::MSR_IA32_LSTAR;
pub use msr_ia32_sfmask::MSR_IA32_SFMASK;
pub use msr_ia32_star::MSR_IA32_STAR;
pub use msr::ia32_apic_base::MSR_IA32_APIC_BASE;
pub use msr::ia32_efer::MSR_IA32_EFER;
pub use msr::ia32_kernel_gs_base::MSR_IA32_KERNEL_GS_BASE;
pub use msr::ia32_lstar::MSR_IA32_LSTAR;
pub use msr::ia32_sfmask::MSR_IA32_SFMASK;
pub use msr::ia32_star::MSR_IA32_STAR;
pub use xcr0::XCR0;
#[repr(C, align(0x10))]
#[repr(C, align(16))]
pub struct FpuContext {
data: [u8; 512],
inner: [u8; 512],
}
impl FpuContext {
pub fn new() -> Self {
let mut value = Self { data: [0; 512] };
unsafe {
let ptr = value.data.as_mut_ptr();
core::arch::asm!("fninit; fxsave64 ({})", in(reg) ptr, options(att_syntax));
}
value
pub const fn new() -> Self {
Self { inner: [0; 512] }
}
/// # Safety
///
/// Only meant to be called from a context switch routine.
pub unsafe fn save(dst: *mut FpuContext) {
core::arch::asm!("fxsave64 ({})", in(reg) dst, options(att_syntax));
pub fn store(this: *mut Self) {
unsafe { core::arch::asm!("fxsave ({})", in(reg) this, options(att_syntax)) }
}
/// # Safety
///
/// Only meant to be called from a context switch routine.
pub unsafe fn restore(src: *mut FpuContext) {
core::arch::asm!("fxrstor64 ({})", in(reg) src, options(att_syntax));
pub fn restore(this: *const Self) {
unsafe { core::arch::asm!("fxrstor ({})", in(reg) this, options(att_syntax)) }
}
}

View File

@ -10,6 +10,8 @@ libk-mm-interface = { path = "../../libk/libk-mm/interface" }
memtables = { path = "../../lib/memtables" }
device-api = { path = "../../lib/device-api", features = ["derive"] }
kernel-arch-x86 = { path = "../x86" }
bitflags = "2.6.0"
static_assertions = "1.1.0"
tock-registers = "0.8.1"

View File

@ -4,10 +4,11 @@ use kernel_arch_interface::{
mem::{KernelTableManager, PhysicalMemoryAllocator},
task::{ForkFrame, StackBuilder, TaskContext, TaskFrame, UserContextInfo},
};
use kernel_arch_x86::registers::FpuContext;
use libk_mm_interface::address::{AsPhysicalAddress, PhysicalAddress};
use yggdrasil_abi::{arch::SavedFrame, error::Error};
use crate::{mem::KERNEL_TABLES, registers::FpuContext};
use crate::mem::KERNEL_TABLES;
/// Frame saved onto the stack when taking an IRQ
#[derive(Debug)]
@ -494,7 +495,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
if dst != src {
// Save the old context
FpuContext::save(from.fpu_context.get());
FpuContext::store(from.fpu_context.get());
// Load next context
FpuContext::restore(self.fpu_context.get());

View File

@ -17,13 +17,12 @@ use kernel_arch_interface::{
util::OneTimeInit,
Architecture,
};
use kernel_arch_x86::{cpuid::CpuFeatures, registers::MSR_IA32_KERNEL_GS_BASE};
use libk_mm_interface::address::PhysicalAddress;
use registers::MSR_IA32_KERNEL_GS_BASE;
use tock_registers::interfaces::Writeable;
pub mod context;
pub mod mem;
pub mod registers;
pub use context::TaskContextImpl;
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
@ -54,6 +53,8 @@ pub struct PerCpuData {
pub tmp_address: usize,
pub local_apic: &'static dyn LocalApicInterface,
pub available_features: CpuFeatures,
pub enabled_features: CpuFeatures,
}
impl PerCpuData {
@ -87,6 +88,7 @@ impl ArchitectureImpl {
impl Architecture for ArchitectureImpl {
type PerCpuData = PerCpuData;
type CpuFeatures = CpuFeatures;
unsafe fn set_local_cpu(cpu: *mut ()) {
MSR_IA32_KERNEL_GS_BASE.set(cpu as u64);
@ -172,4 +174,12 @@ impl Architecture for ArchitectureImpl {
let local = Self::local_cpu_data().unwrap();
local.local_apic
}
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.enabled_features)
}
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
Some(&cpu.available_features)
}
}

View File

@ -8,6 +8,7 @@ use core::{
use kernel_arch_interface::mem::{
DeviceMemoryAttributes, KernelTableManager, RawDeviceMemoryMapping,
};
use kernel_arch_x86::registers::CR3;
use libk_mm_interface::{
address::PhysicalAddress,
table::{page_index, EntryLevel, EntryLevelExt},
@ -17,7 +18,7 @@ use memtables::x86_64::FixedTables;
use static_assertions::{const_assert_eq, const_assert_ne};
use yggdrasil_abi::error::Error;
use crate::{registers::CR3, KERNEL_VIRT_OFFSET};
use crate::KERNEL_VIRT_OFFSET;
use self::table::{PageAttributes, PageEntry, PageTable, L0, L1, L2, L3};

View File

@ -284,7 +284,12 @@ pub fn load<P: AsRef<Path>>(
let space = ProcessAddressSpace::new()?;
let (image, args, envs) = xxx_load_program(&space, ioctx, path, args, envs)?;
setup_binary(path.display(), group_id, parent, space, image, &args, &envs)
let name = path.display();
let name = match name.rsplit_once('/') {
Some((_, name)) => name,
None => name,
};
setup_binary(name, group_id, parent, space, image, &args, &envs)
}
pub fn load_into<P: AsRef<Path>>(

View File

@ -100,7 +100,7 @@ impl Process {
let id = ProcessId::new();
let process = Arc::new(Self {
name,
name: name.clone(),
id,
parent,
@ -111,7 +111,7 @@ impl Process {
});
// Create "main" thread
let thread = Thread::new_uthread(process.id, space, context);
let thread = Thread::new_uthread(process.id, Some(name), space, context);
process.inner.write().register_thread(thread.clone());
MANAGER.register_process(process.clone());
@ -148,7 +148,7 @@ impl Process {
tls: tls_address,
};
let context = TaskContextImpl::user(info)?;
let thread = Thread::new_uthread(self.id, space.clone(), context);
let thread = Thread::new_uthread(self.id, None, space.clone(), context);
let id = thread.id;
inner.register_thread(thread.clone());

View File

@ -150,12 +150,13 @@ impl Thread {
/// Constructs a new user-space thread
pub fn new_uthread(
parent: ProcessId,
name: Option<String>,
space: Arc<ProcessAddressSpace>,
context: TaskContextImpl,
) -> Arc<Self> {
Self::new(
ThreadId::next_user(),
None,
name,
Some(parent),
Some(space),
context,

View File

@ -262,6 +262,7 @@ dependencies = [
"bitflags",
"device-api",
"kernel-arch-interface",
"kernel-arch-x86",
"libk-mm-interface",
"log",
"static_assertions",
@ -277,6 +278,15 @@ dependencies = [
"yggdrasil-abi",
]
[[package]]
name = "kernel-arch-x86"
version = "0.1.0"
dependencies = [
"bitflags",
"kernel-arch-interface",
"tock-registers",
]
[[package]]
name = "kernel-arch-x86_64"
version = "0.1.0"
@ -284,6 +294,7 @@ dependencies = [
"bitflags",
"device-api",
"kernel-arch-interface",
"kernel-arch-x86",
"libk-mm-interface",
"memtables",
"static_assertions",

View File

@ -2,7 +2,9 @@ use core::{arch::global_asm, ptr::addr_of};
use abi::{primitive_enum, process::Signal, SyscallFunction};
use kernel_arch_i686::context::{ExceptionFrame, SyscallFrame};
use kernel_arch_x86::registers::{CR2, CR3};
use libk::task::thread::Thread;
use tock_registers::interfaces::Readable;
use crate::{arch::x86::peripherals::i8259, syscall};
@ -148,15 +150,11 @@ impl Entry {
static mut IDT: [Entry; SIZE] = [Entry::NULL; SIZE];
fn kernel_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) -> ! {
let cr3: usize;
let cr2: usize;
unsafe {
core::arch::asm!("mov %cr3, {0}", out(reg) cr3, options(att_syntax));
core::arch::asm!("mov %cr2, {0}", out(reg) cr2, options(att_syntax));
}
let cr3 = CR3.get();
fatalln!("{:?} in KERNEL, frame {:p}, cr3 = {:#x}", kind, frame, cr3);
if kind == ExceptionKind::PageFault {
let cr2 = CR2.get();
fatalln!("cr2 = {:#x}", cr2);
}
fatalln!("CS:EIP = {:02x}:{:08x}", frame.cs, frame.eip);
@ -164,22 +162,17 @@ fn kernel_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) -> ! {
panic!("Irrecoverable exception")
}
fn user_exception_inner(kind: ExceptionKind, _frame: &ExceptionFrame) {
fn user_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) {
let thread = Thread::current();
let cr3: usize;
unsafe {
core::arch::asm!("mov %cr3, {0}", out(reg) cr3, options(att_syntax));
}
let cr3 = CR3.get();
warnln!("{:?} in {} {:?}", kind, thread.id, thread.name);
warnln!("CS:EIP = {:#02x}:{:#010x}", frame.cs, frame.eip);
warnln!("CR3 = {:#x}", cr3);
match kind {
ExceptionKind::PageFault => {
let cr2: usize;
unsafe {
core::arch::asm!("mov %cr2, {0}", out(reg) cr2, options(att_syntax));
}
let cr2 = CR2.get();
warnln!("CR2 = {:#x}", cr2);
thread.raise_signal(Signal::MemoryAccessViolation);

View File

@ -8,6 +8,7 @@ use device_api::{
use git_version::git_version;
use kernel_arch::{Architecture, ArchitectureImpl};
use kernel_arch_i686::{mem::table::L3, PerCpuData};
use kernel_arch_x86::cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures};
use kernel_fs::devfs::{self, CharDeviceType};
use libk::{
arch::Cpu,
@ -25,9 +26,9 @@ use peripherals::textfb::TextFramebuffer;
use ygg_driver_input::KEYBOARD_DEVICE;
use ygg_driver_pci::{LegacyPciAccess, PciBusManager};
pub mod boot;
mod boot;
pub mod exception;
pub mod peripherals;
mod peripherals;
use crate::{
arch::x86::{
@ -172,7 +173,22 @@ impl I686 {
exception::init_exceptions();
}
let cpu_data = PerCpuData {};
let (have_features, will_features) = cpuid::setup_features(
CpuFeatures {
ecx: EcxFeatures::SSE3 | EcxFeatures::XSAVE | EcxFeatures::OSXSAVE,
edx: EdxFeatures::SSE2 | EdxFeatures::FXSR,
},
CpuFeatures {
ecx: EcxFeatures::empty(),
edx: EdxFeatures::FPU | EdxFeatures::SSE | EdxFeatures::PSE,
},
);
let will_features = will_features.expect("Could not enable needed CPU features");
let cpu_data = PerCpuData {
available_features: have_features,
enabled_features: will_features,
};
Cpu::init_local(Some(0), cpu_data);
runtime::init_task_queue();

View File

@ -10,9 +10,8 @@ use device_api::{
},
Device,
};
use kernel_arch_x86_64::{
mem::table::L3, registers::MSR_IA32_APIC_BASE, LocalApicInterface, CPU_COUNT,
};
use kernel_arch_x86::registers::MSR_IA32_APIC_BASE;
use kernel_arch_x86_64::{mem::table::L3, LocalApicInterface, CPU_COUNT};
use libk::arch::Cpu;
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, table::EntryLevelExt};
use libk_util::{

View File

@ -1,7 +1,8 @@
//! x86-64 boot and entry functions
use core::{arch::global_asm, sync::atomic::Ordering};
use kernel_arch_x86_64::{registers::MSR_IA32_KERNEL_GS_BASE, CPU_COUNT};
use kernel_arch_x86::registers::MSR_IA32_KERNEL_GS_BASE;
use kernel_arch_x86_64::CPU_COUNT;
use kernel_fs::devfs;
use libk::task::runtime;
use tock_registers::interfaces::Writeable;
@ -12,7 +13,7 @@ use yboot_proto::{
use crate::{kernel_main, kernel_secondary_main, mem::KERNEL_VIRT_OFFSET};
use super::{cpuid::init_cpuid, exception, PLATFORM};
use super::{exception, PLATFORM};
pub enum BootData {
YBoot(&'static LoadProtocolV1),
@ -77,9 +78,6 @@ extern "C" fn __x86_64_upper_entry() -> ! {
PLATFORM.set_boot_data(BootData::YBoot(&YBOOT_DATA));
// Gather available CPU features
init_cpuid();
// Setup memory management: kernel virtual memory tables, physical page manager and heap
unsafe {
PLATFORM

View File

@ -1,111 +0,0 @@
//! x86-64 CPUID interface
use bitflags::bitflags;
use kernel_arch_x86_64::registers::{CR4, XCR0};
use libk_util::OneTimeInit;
use tock_registers::interfaces::ReadWriteable;
bitflags! {
pub struct ProcessorFeatures: u64 {
const PDPE1GB = 1 << 0;
}
}
bitflags! {
pub struct EcxFeatures: u32 {
const XSAVE = 1 << 26;
const AVX = 1 << 28;
}
}
bitflags! {
pub struct EdxFeatures: u32 {
const FXSR = 1 << 24;
const PGE = 1 << 13;
}
}
bitflags! {
pub struct ExtEdxFeatures: u32 {
const PDPE1GB = 1 << 26;
}
}
unsafe fn raw_cpuid(eax: u32, result: &mut [u32]) {
core::arch::asm!(
r#"
push %rbx
cpuid
mov %ebx, {0:e}
pop %rbx
"#,
out(reg) result[0],
out("edx") result[1],
out("ecx") result[2],
in("eax") eax,
options(att_syntax)
);
}
fn cpuid_features() -> (EcxFeatures, EdxFeatures) {
let mut raw = [0; 3];
unsafe {
raw_cpuid(0x1, &mut raw);
}
(
EcxFeatures::from_bits_truncate(raw[2]),
EdxFeatures::from_bits_truncate(raw[1]),
)
}
fn cpuid_ext_features() -> ExtEdxFeatures {
let mut raw = [0; 3];
unsafe {
raw_cpuid(0x80000001, &mut raw);
}
ExtEdxFeatures::from_bits_truncate(raw[1])
}
pub static PROCESSOR_FEATURES: OneTimeInit<ProcessorFeatures> = OneTimeInit::new();
pub fn init_cpuid() {
let mut features = ProcessorFeatures::empty();
let ext_edx = cpuid_ext_features();
if ext_edx.contains(ExtEdxFeatures::PDPE1GB) {
features |= ProcessorFeatures::PDPE1GB;
}
PROCESSOR_FEATURES.init(features);
}
pub fn enable_features() {
let (ecx, edx) = cpuid_features();
if !ecx.contains(EcxFeatures::XSAVE) {
panic!("XSAVE feature is required");
}
if !edx.contains(EdxFeatures::FXSR) {
panic!("FXSR feature is required");
}
if !edx.contains(EdxFeatures::PGE) {
todo!("PGE feature (currently) is not optional");
}
CR4.modify(CR4::OSXSAVE::SET + CR4::OSFXSR::SET + CR4::PGE::SET);
// XXX? SSE is supported on all x86-64s
XCR0.modify(XCR0::X87::SET + XCR0::SSE::SET);
if ecx.contains(EcxFeatures::AVX) {
// Enable AVX
XCR0.modify(XCR0::AVX::SET);
}
}

View File

@ -2,7 +2,8 @@
use core::{arch::global_asm, mem::size_of, ptr::addr_of};
use abi::{primitive_enum, process::Signal};
use kernel_arch_x86_64::{context::ExceptionFrame, registers::CR3};
use kernel_arch_x86::registers::{CR2, CR3};
use kernel_arch_x86_64::context::ExceptionFrame;
use libk::{arch::Cpu, task::thread::Thread};
use tock_registers::interfaces::Readable;
@ -132,10 +133,7 @@ fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) {
thread.handle_single_step(frame);
}
ExceptionKind::PageFault => {
let cr2: usize;
unsafe {
core::arch::asm!("mov %cr2, {0}", out(reg) cr2, options(att_syntax));
}
let cr2 = CR2.get();
warnln!("CR2 = {:#x}", cr2);
@ -158,15 +156,11 @@ fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) {
}
fn kernel_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) -> ! {
let cr3: usize;
let cr2: usize;
unsafe {
core::arch::asm!("movq %cr3, {0}", out(reg) cr3, options(att_syntax));
core::arch::asm!("movq %cr2, {0}", out(reg) cr2, options(att_syntax));
}
let cr3 = CR3.get();
fatalln!("{:?} in KERNEL, frame {:p}, cr3 = {:#x}", kind, frame, cr3);
if kind == ExceptionKind::PageFault {
let cr2 = CR2.get();
fatalln!("cr2 = {:#x}", cr2);
}

View File

@ -6,6 +6,7 @@ use acpi_lib::{mcfg::Mcfg, AcpiTables, InterruptModel};
use alloc::boxed::Box;
use device_api::{interrupt::Irq, Device};
use git_version::git_version;
use kernel_arch_x86::cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures};
use kernel_arch_x86_64::{
mem::{
init_fixed_tables,
@ -29,7 +30,6 @@ use ygg_driver_pci::PciBusManager;
mod acpi;
mod apic;
mod boot;
mod cpuid;
mod exception;
mod smp;
mod syscall;
@ -48,7 +48,6 @@ use self::{
acpi::{AcpiAllocator, AcpiHandlerImpl},
apic::{ioapic::IoApic, local::LocalApic},
boot::BootData,
cpuid::{ProcessorFeatures, PROCESSOR_FEATURES},
};
use super::{
@ -160,64 +159,63 @@ impl X86_64 {
MEMORY_LIMIT.store(memory_end.into_usize(), Ordering::Release);
// Check if 1GiB pages are supported
if PROCESSOR_FEATURES
.get()
.contains(ProcessorFeatures::PDPE1GB)
{
// Just map gigabytes of RAM
for l1i in 0..end_l1i {
// TODO NX
unsafe {
RAM_MAPPING_L1[l1i] = PageEntry::<L1>::block(
PhysicalAddress::from_usize(l1i * L1::SIZE),
PageAttributes::WRITABLE,
);
}
}
} else {
// Allocate the intermediate tables first
let l2_tables_start = phys::find_contiguous_region(it, end_l1i)
.expect("Could not allocate the memory for RAM mapping L2 tables");
// TODO
// if PROCESSOR_FEATURES
// .get()
// .contains(ProcessorFeatures::PDPE1GB)
// {
// // Just map gigabytes of RAM
// for l1i in 0..end_l1i {
// // TODO NX
// unsafe {
// RAM_MAPPING_L1[l1i] = PageEntry::<L1>::block(
// PhysicalAddress::from_usize(l1i * L1::SIZE),
// PageAttributes::WRITABLE,
// );
// }
// }
// } else {
// Allocate the intermediate tables first
let l2_tables_start = phys::find_contiguous_region(it, end_l1i)
.expect("Could not allocate the memory for RAM mapping L2 tables");
unsafe {
reserve_region(
"ram-l2-tables",
PhysicalMemoryRegion {
base: l2_tables_start,
size: end_l1i * L3::SIZE,
},
unsafe {
reserve_region(
"ram-l2-tables",
PhysicalMemoryRegion {
base: l2_tables_start,
size: end_l1i * L3::SIZE,
},
);
}
// Fill in the tables
for l1i in 0..end_l1i {
let l2_phys_addr = l2_tables_start.add(l1i * L3::SIZE);
// Safety: ok, the mapping is done to the memory obtained from
// find_contiguous_region()
let mut l2_data = unsafe { EarlyMapping::<[PageEntry<L2>; 512]>::map(l2_phys_addr)? };
// Safety: ok, the slice comes from EarlyMapping of a page-aligned region
let l2 = unsafe { PageTable::from_raw_slice_mut(l2_data.deref_mut()) };
for l2i in 0..512 {
// TODO NX
l2[l2i] = PageEntry::<L2>::block(
PhysicalAddress::from_usize((l1i * L1::SIZE) | (l2i * L2::SIZE)),
PageAttributes::WRITABLE,
);
}
// Fill in the tables
for l1i in 0..end_l1i {
let l2_phys_addr = l2_tables_start.add(l1i * L3::SIZE);
// Point the L1 entry to the L2 table
unsafe {
RAM_MAPPING_L1[l1i] = PageEntry::<L1>::table(l2_phys_addr, PageAttributes::WRITABLE)
};
// Safety: ok, the mapping is done to the memory obtained from
// find_contiguous_region()
let mut l2_data =
unsafe { EarlyMapping::<[PageEntry<L2>; 512]>::map(l2_phys_addr)? };
// Safety: ok, the slice comes from EarlyMapping of a page-aligned region
let l2 = unsafe { PageTable::from_raw_slice_mut(l2_data.deref_mut()) };
for l2i in 0..512 {
// TODO NX
l2[l2i] = PageEntry::<L2>::block(
PhysicalAddress::from_usize((l1i * L1::SIZE) | (l2i * L2::SIZE)),
PageAttributes::WRITABLE,
);
}
// Point the L1 entry to the L2 table
unsafe {
RAM_MAPPING_L1[l1i] =
PageEntry::<L1>::table(l2_phys_addr, PageAttributes::WRITABLE)
};
intrinsics::flush_cpu_cache();
// The EarlyMapping is then dropped
}
intrinsics::flush_cpu_cache();
// The EarlyMapping is then dropped
}
// }
Ok(())
}
@ -260,13 +258,34 @@ impl X86_64 {
let local_apic = Box::leak(Box::new(LocalApic::new()));
let tss_address = gdt::init();
let (have_features, will_features) = cpuid::setup_features(
CpuFeatures {
ecx: EcxFeatures::SSE3
| EcxFeatures::SSE4_1
| EcxFeatures::SSE4_2
| EcxFeatures::AVX,
edx: EdxFeatures::empty(),
},
CpuFeatures {
ecx: EcxFeatures::XSAVE,
edx: EdxFeatures::FXSR
| EdxFeatures::SSE
| EdxFeatures::PGE
| EdxFeatures::PSE
| EdxFeatures::FPU,
},
);
let will_features = will_features.expect("Could not initialize CPU features");
let cpu_data = PerCpuData {
this: null_mut(),
tss_address,
tmp_address: 0,
local_apic,
available_features: have_features,
enabled_features: will_features,
};
cpuid::enable_features();
Cpu::init_local(Some(cpu_id as _), cpu_data);
syscall::init_syscall();

View File

@ -3,10 +3,8 @@
use core::arch::global_asm;
use abi::SyscallFunction;
use kernel_arch_x86_64::{
context::SyscallFrame,
registers::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR},
};
use kernel_arch_x86::registers::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR};
use kernel_arch_x86_64::context::SyscallFrame;
use libk::task::{process::Process, thread::Thread};
use tock_registers::interfaces::{ReadWriteable, Writeable};

View File

@ -5,7 +5,9 @@ use core::sync::atomic::Ordering;
use abi::error::Error;
use alloc::{format, string::String};
use git_version::git_version;
use kernel_arch_interface::cpu::CpuFeatureSet;
use libk::{
arch::Cpu,
task::{cpu_count, sched},
vfs::{
impls::{const_value_node, mdir, read_fn_node, ReadOnlyFnValueNode},
@ -28,6 +30,21 @@ fn read_kernel_log(pos: u64, buffer: &mut [u8]) -> Result<usize, Error> {
Ok(debug::RING_LOGGER_SINK.read(pos as usize, buffer))
}
fn feature_list<C: CpuFeatureSet>(features: Option<&C>) -> String {
let mut list = String::new();
if let Some(features) = features {
let mut cnt = 0;
features.iter().for_each(|feature| {
if cnt != 0 {
list.push(' ');
}
list.push_str(feature);
cnt += 1;
});
}
list
}
fn sched_stats() -> String {
let mut res = String::new();
for i in 0..cpu_count() {
@ -69,8 +86,21 @@ pub fn init() {
),
]);
let d_mem = mdir([("phys", d_mem_phys)]);
// TODO per-CPU entries
let d_cpu_features = mdir([
(
"enabled",
ReadOnlyFnValueNode::new_node(|| Ok(feature_list(Cpu::local().enabled_features()))),
),
(
"available",
ReadOnlyFnValueNode::new_node(|| Ok(feature_list(Cpu::local().available_features()))),
),
]);
let d_cpu = mdir([("features", d_cpu_features)]);
let root = mdir([
("kernel", d_kernel),
("cpu", d_cpu),
("mem", d_mem),
("proc", d_proc),
("arch", const_value_node(util::arch_str())),

View File

@ -1,30 +0,0 @@
//! Binary execution functions
use core::{alloc::Layout, ptr::NonNull};
use abi::{
error::Error,
io::SeekFrom,
pass::{Place, Placer},
path::Path,
process::ProgramArgumentInner,
};
use alloc::{
borrow::ToOwned,
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use kernel_arch::task::TaskContext;
use libk::thread::TaskContextImpl;
use libk_mm::{
pointer::PhysicalRefMut,
process::{ProcessAddressSpace, VirtualRangeBacking},
table::MapAttributes,
};
use libk_thread::{mem::ForeignPointer, process::Process, thread::Thread};
use vfs::{FileRef, IoContext, Read, Seek};
use crate::{
proc,
task::process::{ProcessImage, ProcessImpl},
};