x86-64/mm: limit physical memory, init is slow
This commit is contained in:
parent
d5859d93a9
commit
fbb804f14f
@ -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" }
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -1,57 +1,103 @@
|
||||
//! 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 {
|
||||
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)
|
||||
$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!(
|
||||
"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, ()); };
|
||||
}
|
||||
|
||||
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) {
|
||||
let low = value as u32;
|
||||
let high = (value >> 32) as u32;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"wrmsr",
|
||||
in("ecx") $addr,
|
||||
in("eax") low,
|
||||
in("edx") high,
|
||||
options(att_syntax)
|
||||
);
|
||||
}
|
||||
impl_write!($t, $register, value, {
|
||||
let low = value as u32;
|
||||
let high = (value >> 32) as u32;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"wrmsr",
|
||||
in("ecx") $addr,
|
||||
in("eax") low,
|
||||
in("edx") high,
|
||||
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;
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
out |= Self::WRITABLE;
|
||||
}
|
||||
if flags & PF_X == 0 {
|
||||
out |= Self::NX;
|
||||
}
|
||||
// if flags & PF_W != 0 {
|
||||
out |= Self::WRITABLE;
|
||||
// }
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user