diff --git a/Cargo.toml b/Cargo.toml index 4f800e69..960cd447 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/src/arch/x86_64/boot/mod.rs b/src/arch/x86_64/boot/mod.rs index 679dafdc..7b23deea 100644 --- a/src/arch/x86_64/boot/mod.rs +++ b/src/arch/x86_64/boot/mod.rs @@ -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), diff --git a/src/arch/x86_64/mem/mod.rs b/src/arch/x86_64/mem/mod.rs index 77ee41d2..a5168bfc 100644 --- a/src/arch/x86_64/mem/mod.rs +++ b/src/arch/x86_64/mem/mod.rs @@ -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) { /// * 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); } diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index df67b8eb..37272ea3 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -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)?; } diff --git a/src/arch/x86_64/registers/mod.rs b/src/arch/x86_64/registers/mod.rs index b13cabe9..03e9e70e 100644 --- a/src/arch/x86_64/registers/mod.rs +++ b/src/arch/x86_64/registers/mod.rs @@ -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; diff --git a/src/main.rs b/src/main.rs index c7171e96..bdb659c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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)] diff --git a/src/mem/phys/mod.rs b/src/mem/phys/mod.rs index 1b691cf1..e1328d03 100644 --- a/src/mem/phys/mod.rs +++ b/src/mem/phys/mod.rs @@ -163,14 +163,21 @@ pub unsafe fn init_from_iter + 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; } } diff --git a/tools/gentables/src/x86_64.rs b/tools/gentables/src/x86_64.rs index 8ce01464..d41551a4 100644 --- a/tools/gentables/src/x86_64.rs +++ b/tools/gentables/src/x86_64.rs @@ -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 { 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 X8664Builder { } 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(); }