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]
yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }
aml = { git = "https://github.com/alnyan/acpi.git", version = "0.16.4" }
acpi_lib = { git = "https://github.com/alnyan/acpi.git", version = "4.1.1", package = "acpi" }
acpi-system = { git = "https://github.com/alnyan/acpi-system.git", version = "0.1.0" }
aml = { git = "https://github.com/alnyan/acpi.git", branch = "acpi-system" }
acpi_lib = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branch = "acpi-system" }
acpi-system = { git = "https://github.com/alnyan/acpi-system.git" }
# TODO currently only supported here
xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }

View File

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

View File

@ -5,14 +5,15 @@ use core::{
use abi::error::Error;
use kernel_util::util::OneTimeInit;
use memtables::FixedTables;
use memtables::{FixedTables, KERNEL_L3_COUNT};
use static_assertions::{const_assert_eq, const_assert_ne};
pub mod process;
pub mod table;
use crate::{
arch::x86_64::{intrinsics, mem::table::PageAttributes},
arch::x86_64::{intrinsics, mem::table::PageAttributes, registers::CR3},
device::display::font::PcScreenFont,
mem::{
address::{FromRaw, IntoRaw, KernelImageObject},
device::RawDeviceMemoryMapping,
@ -318,6 +319,7 @@ fn clone_kernel_tables(dst: &mut PageTable<L0>) {
/// * 0xFFFFFF8080000000 .. 0xFFFFFF8080800000 : DEVICE_MAPPING_L3S
/// * 0xFFFFFF8080800000 .. 0xFFFFFF8100000000 : ...
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 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;
@ -330,19 +332,22 @@ pub unsafe fn init_fixed_tables() {
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)
| (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
assert_eq!(KERNEL_TABLES.kernel_l1.data[HEAP_MAPPING_L1I], 0);
KERNEL_TABLES.kernel_l1.data[HEAP_MAPPING_L1I] =
(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)
| (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
assert_eq!(KERNEL_TABLES.l0.data[RAM_MAPPING_L0I], 0);
KERNEL_TABLES.l0.data[RAM_MAPPING_L0I] =
(ram_mapping_l1_phys as u64) | (PageAttributes::WRITABLE | PageAttributes::PRESENT).bits();
// TODO ENABLE EFER.NXE
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();
infoln!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
let ps2 = Box::leak(Box::new(PS2Controller::new(
IrqNumber::Isa(1),
IrqNumber::Isa(12),
@ -398,12 +404,6 @@ impl X86_64 {
)));
ps2.init()?;
infoln!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi)?;
}

View File

@ -1,13 +1,36 @@
//! Helper types for interfacing with x86-64 registers
macro_rules! msr_impl_read {
($t:ident, $addr:expr, $register:ty) => {
macro_rules! impl_read {
($t:ident, $register:ty, $body:expr) => {
impl tock_registers::interfaces::Readable for $t {
type T = u64;
type R = $register;
#[inline]
fn get(&self) -> u64 {
$body
}
}
};
}
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!(
@ -19,8 +42,7 @@ macro_rules! msr_impl_read {
);
}
((high as u64) << 32) | (low as u64)
}
}
});
};
($t:ident, $addr:expr) => { msr_impl_read!($t, $addr, ()); };
@ -28,12 +50,7 @@ macro_rules! msr_impl_read {
macro_rules! msr_impl_write {
($t:ident, $addr:expr, $register:ty) => {
impl tock_registers::interfaces::Writeable for $t {
type T = u64;
type R = $register;
#[inline]
fn set(&self, value: u64) {
impl_write!($t, $register, value, {
let low = value as u32;
let high = (value >> 32) as u32;
unsafe {
@ -45,13 +62,42 @@ macro_rules! msr_impl_write {
options(att_syntax)
);
}
}
}
});
};
($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;
@ -182,12 +228,73 @@ mod msr_ia32_efer {
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::{
interfaces::{Readable, Writeable},
interfaces::{ReadWriteable, Readable},
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! {
u64,
#[allow(missing_docs)]
@ -196,36 +303,28 @@ mod cr4 {
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(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;
impl Readable for Reg {
type T = u64;
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));
}
}
}
cr_impl_read!(Reg, cr4, CR4::Register);
cr_impl_write!(Reg, cr4, CR4::Register);
/// x86-64 control register 4
pub const CR4: Reg = Reg;
@ -295,6 +394,8 @@ mod xcr0 {
pub const XCR0: Reg = Reg;
}
pub use cr0::CR0;
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;

View File

@ -6,6 +6,7 @@
asm_const,
panic_info_message,
optimize_attribute,
effects,
const_trait_impl,
maybe_uninit_slice,
arbitrary_self_types,
@ -14,7 +15,7 @@
linked_list_cursors,
rustc_private,
allocator_api,
async_fn_in_trait,
trait_alias,
strict_provenance
)]
#![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 collected = 0;
const MAX_MEMORY: usize = 16 * 1024;
for (start, end) in it.into_iter().filter_map(PhysicalMemoryRegion::clamp) {
for page in (start..end).step_by(0x1000) {
if collected >= MAX_MEMORY {
break;
}
if is_reserved(page) {
continue;
}
manager.add_available_page(page);
collected += 1;
}
}

View File

@ -20,7 +20,7 @@ bitflags! {
struct PageFlags: u64 {
const PRESENT = 1 << 0;
const WRITABLE = 1 << 1;
const NX = 1 << 63;
// const NX = 1 << 63;
}
}
@ -38,12 +38,12 @@ pub struct X8664Builder<F: Seek + Read> {
impl PageFlags {
fn from_elf(flags: u32) -> Self {
let mut out = Self::empty();
if flags & PF_W != 0 {
// if flags & PF_W != 0 {
out |= Self::WRITABLE;
}
if flags & PF_X == 0 {
out |= Self::NX;
}
// }
// if flags & PF_X == 0 {
// // out |= Self::NX;
// }
out
}
}
@ -58,7 +58,7 @@ impl fmt::Display for PageFlags {
} 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> {
// L0 -> L1
assert_eq!(offset_of!(FixedTables, l0), 0);
let l1_physical_address =
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] =
l1_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits();
// 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] =
l2_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits();
// 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
+ (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();
}