x86: better cpuid interface
This commit is contained in:
parent
82d1af7b89
commit
7a3acff20d
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -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",
|
||||
|
@ -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"]
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
@ -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> {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
13
kernel/arch/x86/Cargo.toml
Normal file
13
kernel/arch/x86/Cargo.toml
Normal 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)'] }
|
253
kernel/arch/x86/src/cpuid.rs
Normal file
253
kernel/arch/x86/src/cpuid.rs
Normal 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))
|
||||
}
|
5
kernel/arch/x86/src/lib.rs
Normal file
5
kernel/arch/x86/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#![feature(iter_chain)]
|
||||
#![no_std]
|
||||
|
||||
pub mod cpuid;
|
||||
pub mod registers;
|
@ -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)) }
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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>>(
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
11
kernel/modules/test_mod/Cargo.lock
generated
11
kernel/modules/test_mod/Cargo.lock
generated
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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::{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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())),
|
||||
|
@ -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},
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user