x86-64/mm: limit physical memory, init is slow

This commit is contained in:
Mark Poliakov 2023-11-06 10:29:53 +02:00
parent d5859d93a9
commit fbb804f14f
8 changed files with 208 additions and 88 deletions

View File

@ -43,9 +43,9 @@ fdt-rs = { version = "0.4.3", default-features = false }
[target.'cfg(target_arch = "x86_64")'.dependencies] [target.'cfg(target_arch = "x86_64")'.dependencies]
yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" } yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }
aml = { git = "https://github.com/alnyan/acpi.git", version = "0.16.4" } aml = { git = "https://github.com/alnyan/acpi.git", branch = "acpi-system" }
acpi_lib = { git = "https://github.com/alnyan/acpi.git", version = "4.1.1", package = "acpi" } acpi_lib = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branch = "acpi-system" }
acpi-system = { git = "https://github.com/alnyan/acpi-system.git", version = "0.1.0" } acpi-system = { git = "https://github.com/alnyan/acpi-system.git" }
# TODO currently only supported here # TODO currently only supported here
xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" } xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }

View File

@ -1,21 +1,24 @@
//! x86-64 boot and entry functions //! x86-64 boot and entry functions
use core::{arch::global_asm, sync::atomic::Ordering}; use core::{arch::global_asm, sync::atomic::Ordering};
use tock_registers::interfaces::Writeable; use tock_registers::interfaces::{ReadWriteable, Writeable};
use yboot_proto::{ use yboot_proto::{
v1::{FramebufferOption, MemoryMap}, v1::{FramebufferOption, MemoryMap},
LoadProtocolHeader, LoadProtocolV1, KERNEL_MAGIC, LOADER_MAGIC, PROTOCOL_VERSION_1, LoadProtocolHeader, LoadProtocolV1, KERNEL_MAGIC, LOADER_MAGIC, PROTOCOL_VERSION_1,
}; };
use crate::{ use crate::{
arch::x86_64::{registers::MSR_IA32_KERNEL_GS_BASE, smp::CPU_COUNT}, arch::x86_64::{
registers::{CR0, MSR_IA32_KERNEL_GS_BASE},
smp::CPU_COUNT,
},
fs::devfs, fs::devfs,
kernel_main, kernel_secondary_main, kernel_main, kernel_secondary_main,
mem::KERNEL_VIRT_OFFSET, mem::KERNEL_VIRT_OFFSET,
task::runtime, task::runtime,
}; };
use super::{cpuid::init_cpuid, exception, ARCHITECTURE}; use super::{cpuid::init_cpuid, exception, registers::CR4, ARCHITECTURE};
pub enum BootData { pub enum BootData {
YBoot(&'static LoadProtocolV1), YBoot(&'static LoadProtocolV1),

View File

@ -5,14 +5,15 @@ use core::{
use abi::error::Error; use abi::error::Error;
use kernel_util::util::OneTimeInit; use kernel_util::util::OneTimeInit;
use memtables::FixedTables; use memtables::{FixedTables, KERNEL_L3_COUNT};
use static_assertions::{const_assert_eq, const_assert_ne}; use static_assertions::{const_assert_eq, const_assert_ne};
pub mod process; pub mod process;
pub mod table; pub mod table;
use crate::{ use crate::{
arch::x86_64::{intrinsics, mem::table::PageAttributes}, arch::x86_64::{intrinsics, mem::table::PageAttributes, registers::CR3},
device::display::font::PcScreenFont,
mem::{ mem::{
address::{FromRaw, IntoRaw, KernelImageObject}, address::{FromRaw, IntoRaw, KernelImageObject},
device::RawDeviceMemoryMapping, device::RawDeviceMemoryMapping,
@ -318,6 +319,7 @@ fn clone_kernel_tables(dst: &mut PageTable<L0>) {
/// * 0xFFFFFF8080000000 .. 0xFFFFFF8080800000 : DEVICE_MAPPING_L3S /// * 0xFFFFFF8080000000 .. 0xFFFFFF8080800000 : DEVICE_MAPPING_L3S
/// * 0xFFFFFF8080800000 .. 0xFFFFFF8100000000 : ... /// * 0xFFFFFF8080800000 .. 0xFFFFFF8100000000 : ...
pub unsafe fn init_fixed_tables() { pub unsafe fn init_fixed_tables() {
// TODO this could be built in compile-time too?
let early_mapping_l3_phys = &EARLY_MAPPING_L3 as *const _ as usize - KERNEL_VIRT_OFFSET; let early_mapping_l3_phys = &EARLY_MAPPING_L3 as *const _ as usize - KERNEL_VIRT_OFFSET;
let device_mapping_l2_phys = &DEVICE_MAPPING_L2 as *const _ as usize - KERNEL_VIRT_OFFSET; let device_mapping_l2_phys = &DEVICE_MAPPING_L2 as *const _ as usize - KERNEL_VIRT_OFFSET;
let heap_mapping_l2_phys = &HEAP_MAPPING_L2 as *const _ as usize - KERNEL_VIRT_OFFSET; let heap_mapping_l2_phys = &HEAP_MAPPING_L2 as *const _ as usize - KERNEL_VIRT_OFFSET;
@ -330,19 +332,22 @@ pub unsafe fn init_fixed_tables() {
DEVICE_MAPPING_L2[i] = PageEntry::table(device_mapping_l3_phys, PageAttributes::WRITABLE); DEVICE_MAPPING_L2[i] = PageEntry::table(device_mapping_l3_phys, PageAttributes::WRITABLE);
} }
assert_eq!(KERNEL_TABLES.kernel_l2.data[EARLY_MAPPING_L2I], 0);
KERNEL_TABLES.kernel_l2.data[EARLY_MAPPING_L2I] = (early_mapping_l3_phys as u64) KERNEL_TABLES.kernel_l2.data[EARLY_MAPPING_L2I] = (early_mapping_l3_phys as u64)
| (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits(); | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
assert_eq!(KERNEL_TABLES.kernel_l1.data[HEAP_MAPPING_L1I], 0);
KERNEL_TABLES.kernel_l1.data[HEAP_MAPPING_L1I] = KERNEL_TABLES.kernel_l1.data[HEAP_MAPPING_L1I] =
(heap_mapping_l2_phys as u64) | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits(); (heap_mapping_l2_phys as u64) | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
assert_eq!(KERNEL_TABLES.kernel_l1.data[DEVICE_MAPPING_L1I], 0);
KERNEL_TABLES.kernel_l1.data[DEVICE_MAPPING_L1I] = (device_mapping_l2_phys as u64) KERNEL_TABLES.kernel_l1.data[DEVICE_MAPPING_L1I] = (device_mapping_l2_phys as u64)
| (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits(); | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
assert_eq!(KERNEL_TABLES.l0.data[RAM_MAPPING_L0I], 0);
KERNEL_TABLES.l0.data[RAM_MAPPING_L0I] = KERNEL_TABLES.l0.data[RAM_MAPPING_L0I] =
(ram_mapping_l1_phys as u64) | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits(); (ram_mapping_l1_phys as u64) | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
// TODO ENABLE EFER.NXE // TODO ENABLE EFER.NXE
let cr3 = &KERNEL_TABLES.l0 as *const _ as usize - KERNEL_VIRT_OFFSET; let cr3 = &KERNEL_TABLES.l0 as *const _ as usize - KERNEL_VIRT_OFFSET;
core::arch::asm!("wbinvd; mov {0}, %cr3", in(reg) cr3, options(att_syntax)); CR3.set_address(cr3);
} }

View File

@ -390,6 +390,12 @@ impl X86_64 {
debug::init(); debug::init();
infoln!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
let ps2 = Box::leak(Box::new(PS2Controller::new( let ps2 = Box::leak(Box::new(PS2Controller::new(
IrqNumber::Isa(1), IrqNumber::Isa(1),
IrqNumber::Isa(12), IrqNumber::Isa(12),
@ -398,12 +404,6 @@ impl X86_64 {
))); )));
ps2.init()?; ps2.init()?;
infoln!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
if let Some(acpi) = self.acpi.try_get() { if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi)?; self.init_platform_from_acpi(acpi)?;
} }

View File

@ -1,57 +1,103 @@
//! Helper types for interfacing with x86-64 registers //! Helper types for interfacing with x86-64 registers
macro_rules! msr_impl_read { macro_rules! impl_read {
($t:ident, $addr:expr, $register:ty) => { ($t:ident, $register:ty, $body:expr) => {
impl tock_registers::interfaces::Readable for $t { impl tock_registers::interfaces::Readable for $t {
type T = u64; type T = u64;
type R = $register; type R = $register;
#[inline] #[inline]
fn get(&self) -> u64 { fn get(&self) -> u64 {
let (high, low): (u32, u32); $body
unsafe {
core::arch::asm!(
"rdmsr",
in("ecx") $addr,
out("eax") low,
out("edx") high,
options(att_syntax)
);
}
((high as u64) << 32) | (low as u64)
} }
} }
}; };
}
macro_rules! impl_write {
($t:ident, $register:ty, $value:ident, $body:expr) => {
impl tock_registers::interfaces::Writeable for $t {
type T = u64;
type R = $register;
#[inline]
fn set(&self, $value: u64) {
$body
}
}
};
}
macro_rules! msr_impl_read {
($t:ident, $addr:expr, $register:ty) => {
impl_read!($t, $register, {
let (high, low): (u32, u32);
unsafe {
core::arch::asm!(
"rdmsr",
in("ecx") $addr,
out("eax") low,
out("edx") high,
options(att_syntax)
);
}
((high as u64) << 32) | (low as u64)
});
};
($t:ident, $addr:expr) => { msr_impl_read!($t, $addr, ()); }; ($t:ident, $addr:expr) => { msr_impl_read!($t, $addr, ()); };
} }
macro_rules! msr_impl_write { macro_rules! msr_impl_write {
($t:ident, $addr:expr, $register:ty) => { ($t:ident, $addr:expr, $register:ty) => {
impl tock_registers::interfaces::Writeable for $t { impl_write!($t, $register, value, {
type T = u64; let low = value as u32;
type R = $register; let high = (value >> 32) as u32;
unsafe {
#[inline] core::arch::asm!(
fn set(&self, value: u64) { "wrmsr",
let low = value as u32; in("ecx") $addr,
let high = (value >> 32) as u32; in("eax") low,
unsafe { in("edx") high,
core::arch::asm!( options(att_syntax)
"wrmsr", );
in("ecx") $addr,
in("eax") low,
in("edx") high,
options(att_syntax)
);
}
} }
} });
}; };
($t:ident, $addr:expr) => { msr_impl_write!($t, $addr, ()); }; ($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 { mod msr_ia32_kernel_gs_base {
const ADDR: u32 = 0xC0000102; const ADDR: u32 = 0xC0000102;
pub struct Reg; pub struct Reg;
@ -182,12 +228,73 @@ mod msr_ia32_efer {
pub const MSR_IA32_EFER: Reg = Reg; pub const MSR_IA32_EFER: Reg = Reg;
} }
mod cr4 { mod cr0 {
use tock_registers::register_bitfields;
register_bitfields! {
u64,
#[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::{ use tock_registers::{
interfaces::{Readable, Writeable}, interfaces::{ReadWriteable, Readable},
register_bitfields, register_bitfields,
}; };
register_bitfields! {
u64,
#[allow(missing_docs)]
pub CR3 [
ADDR OFFSET(12) NUMBITS(40) [],
]
}
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 u64) >> 12))
}
pub fn address(&self) -> usize {
(self.read(CR3::ADDR) as usize) << 12
}
}
/// x86-64 control register 3
pub const CR3: Reg = Reg;
}
mod cr4 {
use tock_registers::register_bitfields;
register_bitfields! { register_bitfields! {
u64, u64,
#[allow(missing_docs)] #[allow(missing_docs)]
@ -196,36 +303,28 @@ mod cr4 {
OSXSAVE OFFSET(18) NUMBITS(1) [], OSXSAVE OFFSET(18) NUMBITS(1) [],
/// Indicates OS support for FXSAVE and FXRSTOR instructions /// Indicates OS support for FXSAVE and FXRSTOR instructions
OSFXSR OFFSET(9) NUMBITS(1) [], OSFXSR OFFSET(9) NUMBITS(1) [],
/// Performance-Monitoring Counter enable
PCE OFFSET(8) NUMBITS(1) [],
/// If set, "page global" attribute is enabled /// If set, "page global" attribute is enabled
PGE OFFSET(8) NUMBITS(1) [], 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; pub struct Reg;
impl Readable for Reg { cr_impl_read!(Reg, cr4, CR4::Register);
type T = u64; cr_impl_write!(Reg, cr4, CR4::Register);
type R = CR4::Register;
fn get(&self) -> Self::T {
let value: u64;
unsafe {
core::arch::asm!("mov %cr4, {0}", out(reg) value, options(att_syntax));
}
value
}
}
impl Writeable for Reg {
type T = u64;
type R = CR4::Register;
fn set(&self, value: Self::T) {
unsafe {
core::arch::asm!("mov {0}, %cr4", in(reg) value, options(att_syntax));
}
}
}
/// x86-64 control register 4 /// x86-64 control register 4
pub const CR4: Reg = Reg; pub const CR4: Reg = Reg;
@ -295,6 +394,8 @@ mod xcr0 {
pub const XCR0: Reg = Reg; pub const XCR0: Reg = Reg;
} }
pub use cr0::CR0;
pub use cr3::CR3;
pub use cr4::CR4; pub use cr4::CR4;
pub use msr_ia32_apic_base::MSR_IA32_APIC_BASE; pub use msr_ia32_apic_base::MSR_IA32_APIC_BASE;
pub use msr_ia32_efer::MSR_IA32_EFER; pub use msr_ia32_efer::MSR_IA32_EFER;

View File

@ -6,6 +6,7 @@
asm_const, asm_const,
panic_info_message, panic_info_message,
optimize_attribute, optimize_attribute,
effects,
const_trait_impl, const_trait_impl,
maybe_uninit_slice, maybe_uninit_slice,
arbitrary_self_types, arbitrary_self_types,
@ -14,7 +15,7 @@
linked_list_cursors, linked_list_cursors,
rustc_private, rustc_private,
allocator_api, allocator_api,
async_fn_in_trait, trait_alias,
strict_provenance strict_provenance
)] )]
#![allow(clippy::new_without_default, clippy::fn_to_numeric_cast)] #![allow(clippy::new_without_default, clippy::fn_to_numeric_cast)]

View File

@ -163,14 +163,21 @@ pub unsafe fn init_from_iter<I: Iterator<Item = PhysicalMemoryRegion> + Clone>(
); );
let mut manager = PhysicalMemoryManager::new(page_bitmap_phys_base, total_count); let mut manager = PhysicalMemoryManager::new(page_bitmap_phys_base, total_count);
let mut collected = 0;
const MAX_MEMORY: usize = 16 * 1024;
for (start, end) in it.into_iter().filter_map(PhysicalMemoryRegion::clamp) { for (start, end) in it.into_iter().filter_map(PhysicalMemoryRegion::clamp) {
for page in (start..end).step_by(0x1000) { for page in (start..end).step_by(0x1000) {
if collected >= MAX_MEMORY {
break;
}
if is_reserved(page) { if is_reserved(page) {
continue; continue;
} }
manager.add_available_page(page); manager.add_available_page(page);
collected += 1;
} }
} }

View File

@ -20,7 +20,7 @@ bitflags! {
struct PageFlags: u64 { struct PageFlags: u64 {
const PRESENT = 1 << 0; const PRESENT = 1 << 0;
const WRITABLE = 1 << 1; const WRITABLE = 1 << 1;
const NX = 1 << 63; // const NX = 1 << 63;
} }
} }
@ -38,12 +38,12 @@ pub struct X8664Builder<F: Seek + Read> {
impl PageFlags { impl PageFlags {
fn from_elf(flags: u32) -> Self { fn from_elf(flags: u32) -> Self {
let mut out = Self::empty(); let mut out = Self::empty();
if flags & PF_W != 0 { // if flags & PF_W != 0 {
out |= Self::WRITABLE; out |= Self::WRITABLE;
} // }
if flags & PF_X == 0 { // if flags & PF_X == 0 {
out |= Self::NX; // // out |= Self::NX;
} // }
out out
} }
} }
@ -58,7 +58,7 @@ impl fmt::Display for PageFlags {
} else { } else {
'-' '-'
}, },
if self.contains(Self::NX) { '-' } else { 'x' } 'x' // if self.contains(Self::NX) { '-' } else { 'x' }
) )
} }
} }
@ -98,24 +98,27 @@ impl<F: Seek + Read> X8664Builder<F> {
} }
pub fn build(mut self) -> Result<(FixedTables, u64), GenError> { pub fn build(mut self) -> Result<(FixedTables, u64), GenError> {
// L0 -> L1 assert_eq!(offset_of!(FixedTables, l0), 0);
let l1_physical_address = let l1_physical_address =
self.data.table_physical_address + offset_of!(FixedTables, kernel_l1) as u64; self.data.table_physical_address + offset_of!(FixedTables, kernel_l1) as u64;
let l2_physical_address =
self.data.table_physical_address + offset_of!(FixedTables, kernel_l2) as u64;
// L0 -> L1
self.tables.l0.data[self.l0i] = self.tables.l0.data[self.l0i] =
l1_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits(); l1_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits();
// L1 -> L2 // L1 -> L2
let l2_physical_address =
self.data.table_physical_address + offset_of!(FixedTables, kernel_l2) as u64;
self.tables.kernel_l1.data[self.l1i] = self.tables.kernel_l1.data[self.l1i] =
l2_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits(); l2_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits();
// L2 -> L3s // L2 -> L3s
for i in 0..KERNEL_L3_COUNT { for l2i in self.start_l2i..self.end_l2i {
let l3_table_index = l2i - self.start_l2i;
let l3_physical_address = self.data.table_physical_address let l3_physical_address = self.data.table_physical_address
+ (offset_of!(FixedTables, kernel_l3s) + 0x1000 * i) as u64; + (offset_of!(FixedTables, kernel_l3s) + 0x1000 * l3_table_index) as u64;
self.tables.kernel_l2.data[i + self.start_l2i] = self.tables.kernel_l2.data[l2i] =
l3_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits(); l3_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits();
} }