From fe4c2f7c77d44455d3742cf83089d9456d5b7602 Mon Sep 17 00:00:00 2001 From: Mark Poliakov <mark@alnyan.me> Date: Thu, 19 Aug 2021 18:33:58 +0300 Subject: [PATCH] AA --- Cargo.lock | 44 +++ Cargo.toml | 9 +- address/Cargo.toml | 9 + address/src/base/mod.rs | 0 address/src/lib.rs | 19 ++ address/src/phys.rs | 154 +++++++++ address/src/virt.rs | 344 ++++++++++++++++++++ error/Cargo.toml | 8 + error/src/lib.rs | 6 + etc/aarch64-unknown-none-rpi3b.ld | 13 +- etc/gdbrc | 2 +- {.cargo => kernel/.cargo}/config.toml | 2 +- kernel/Cargo.toml | 11 + src/main.rs => kernel/src/arch/exception.rs | 25 +- kernel/src/arch/mod.rs | 1 + kernel/src/arch/vectors.S | 75 +++++ {src => kernel/src}/boot/entry.S | 84 +---- {src => kernel/src}/boot/mod.rs | 0 kernel/src/debug.rs | 28 ++ kernel/src/main.rs | 61 ++++ kernel/src/mem/address.rs | 0 kernel/src/mem/mod.rs | 21 ++ kernel/src/mem/phys/manager.rs | 62 ++++ kernel/src/mem/phys/mod.rs | 118 +++++++ kernel/src/mem/phys/pbox.rs | 24 ++ kernel/src/mem/phys/reserved.rs | 79 +++++ src/lib.rs | 0 27 files changed, 1090 insertions(+), 109 deletions(-) create mode 100644 address/Cargo.toml create mode 100644 address/src/base/mod.rs create mode 100644 address/src/lib.rs create mode 100644 address/src/phys.rs create mode 100644 address/src/virt.rs create mode 100644 error/Cargo.toml create mode 100644 error/src/lib.rs rename {.cargo => kernel/.cargo}/config.toml (55%) create mode 100644 kernel/Cargo.toml rename src/main.rs => kernel/src/arch/exception.rs (58%) create mode 100644 kernel/src/arch/mod.rs create mode 100644 kernel/src/arch/vectors.S rename {src => kernel/src}/boot/entry.S (70%) rename {src => kernel/src}/boot/mod.rs (100%) create mode 100644 kernel/src/debug.rs create mode 100644 kernel/src/main.rs create mode 100644 kernel/src/mem/address.rs create mode 100644 kernel/src/mem/mod.rs create mode 100644 kernel/src/mem/phys/manager.rs create mode 100644 kernel/src/mem/phys/mod.rs create mode 100644 kernel/src/mem/phys/pbox.rs create mode 100644 kernel/src/mem/phys/reserved.rs create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fba3096..155c4a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,50 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "address" +version = "0.1.0" +dependencies = [ + "error", +] + +[[package]] +name = "error" +version = "0.1.0" + +[[package]] +name = "kernel" +version = "0.1.0" +dependencies = [ + "address", + "error", + "spin", +] + +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + [[package]] name = "osdev4" version = "0.1.0" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "spin" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +dependencies = [ + "lock_api", +] diff --git a/Cargo.toml b/Cargo.toml index 371f64c..be072a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "osdev4" version = "0.1.0" edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] +[workspace] +members = [ + "kernel", + "error", + "address" +] diff --git a/address/Cargo.toml b/address/Cargo.toml new file mode 100644 index 0000000..73486c9 --- /dev/null +++ b/address/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "address" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +error = { path = "../error" } diff --git a/address/src/base/mod.rs b/address/src/base/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/address/src/lib.rs b/address/src/lib.rs new file mode 100644 index 0000000..f069084 --- /dev/null +++ b/address/src/lib.rs @@ -0,0 +1,19 @@ +//! Type-safe wrappers for different address kinds +#![no_std] +#![feature( + step_trait, + const_fn_trait_bound +)] +// #![warn(missing_docs)] + +#[cfg(test)] +#[macro_use] +extern crate std; + +pub mod virt; +pub mod phys; + +trait Address {} + +pub use phys::PhysicalAddress; +pub use virt::{AddressSpace, NoTrivialConvert, TrivialConvert, VirtualAddress}; diff --git a/address/src/phys.rs b/address/src/phys.rs new file mode 100644 index 0000000..34fadec --- /dev/null +++ b/address/src/phys.rs @@ -0,0 +1,154 @@ +use crate::{AddressSpace, TrivialConvert, VirtualAddress}; +use core::convert::TryFrom; +use core::fmt; +use core::iter::Step; +use core::ops::{Add, AddAssign, Neg, Sub, SubAssign}; + +#[repr(transparent)] +#[derive(PartialEq, PartialOrd, Copy, Clone)] +pub struct PhysicalAddress(usize); + +// Arithmetic +impl<A: Into<usize>> Add<A> for PhysicalAddress { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: A) -> Self { + // Will panic on overflow + Self::from(self.0 + rhs.into()) + } +} +impl<A: Into<usize>> AddAssign<A> for PhysicalAddress { + #[inline(always)] + fn add_assign(&mut self, rhs: A) { + // Will panic on overflow + *self = Self::from(self.0 + rhs.into()); + } +} +impl Sub<usize> for PhysicalAddress { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self { + Self::from(self.0 - rhs) + } +} +impl SubAssign<usize> for PhysicalAddress { + #[inline(always)] + fn sub_assign(&mut self, rhs: usize) { + *self = Self::from(self.0 - rhs); + } +} + +// Construction +impl From<usize> for PhysicalAddress { + fn from(p: usize) -> Self { + Self(p) + } +} + +#[cfg(target_pointer_width = "64")] +impl From<u64> for PhysicalAddress { + fn from(p: u64) -> Self { + Self(p as usize) + } +} + +impl PhysicalAddress { + #[inline(always)] + pub fn diff(start: PhysicalAddress, end: PhysicalAddress) -> isize { + if end >= start { + isize::try_from(end.0 - start.0).expect("Address subtraction overflowed") + } else { + -isize::try_from(start.0 - end.0).expect("Address subtraction overflowed") + } + } + + #[inline(always)] + pub fn diff_unchecked(start: PhysicalAddress, end: PhysicalAddress) -> isize { + end.0 as isize - start.0 as isize + } + + #[inline(always)] + pub const fn is_paligned(self) -> bool { + return self.0 & 0xFFF == 0 + } + + #[inline(always)] + pub const fn page_index(self) -> usize { + self.0 >> 12 + } +} + +// Trivial conversion PhysicalAddress -> VirtualAddress +impl<T: AddressSpace + TrivialConvert> From<PhysicalAddress> for VirtualAddress<T> { + fn from(p: PhysicalAddress) -> Self { + VirtualAddress::from(p.0 + T::OFFSET) + } +} + +// Formatting +impl fmt::Debug for PhysicalAddress { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "<phys {:#018x}>", self.0) + } +} + +// Step +impl Step for PhysicalAddress { + #[inline] + fn steps_between(_p0: &Self, _p1: &Self) -> Option<usize> { + todo!() + } + + #[inline] + fn forward_checked(p: Self, steps: usize) -> Option<Self> { + p.0.checked_add(steps).map(Self::from) + } + + #[inline] + fn backward_checked(p: Self, steps: usize) -> Option<Self> { + p.0.checked_sub(steps).map(Self::from) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{AddressSpace, NoTrivialConvert, TrivialConvert, VirtualAddress}; + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + struct S0; + impl AddressSpace for S0 { + const NAME: &'static str = "S0"; + const OFFSET: usize = 0x8000; + const LIMIT: usize = Self::OFFSET + 0x4000; + } + impl TrivialConvert for S0 {} + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + struct S1; + impl AddressSpace for S1 { + const NAME: &'static str = "S1"; + const OFFSET: usize = 0; + const LIMIT: usize = 0; + } + impl NoTrivialConvert for S1 {} + + #[test] + fn test_virt_convert_valid() { + let p0 = PhysicalAddress::from(0x1234usize); + assert_eq!( + VirtualAddress::<S0>::from(p0), + VirtualAddress::<S0>::from(0x9234usize) + ); + } + + #[test] + #[should_panic] + fn test_virt_convert_invalid() { + let p0 = PhysicalAddress::from(0x4321usize); + let _v = VirtualAddress::<S0>::from(p0); + } +} diff --git a/address/src/virt.rs b/address/src/virt.rs new file mode 100644 index 0000000..39aa711 --- /dev/null +++ b/address/src/virt.rs @@ -0,0 +1,344 @@ +use super::PhysicalAddress; +use core::convert::TryFrom; +use core::fmt; +use core::iter::Step; +use core::marker::PhantomData; +use core::ops::{Add, AddAssign, Neg, Sub, SubAssign}; + +pub trait AddressSpace: Copy + Clone + PartialEq + PartialOrd { + const NAME: &'static str; + const OFFSET: usize; + const LIMIT: usize; +} + +pub trait NoTrivialConvert {} +pub trait TrivialConvert {} + +#[repr(transparent)] +#[derive(Copy, Clone, PartialOrd, PartialEq)] +pub struct VirtualAddress<Kind: AddressSpace>(usize, PhantomData<Kind>); + +// Arithmetic +impl<T: AddressSpace> Add<usize> for VirtualAddress<T> { + type Output = Self; + + #[inline(always)] + fn add(self, rhs: usize) -> Self { + // Will panic on overflow + Self::from(self.0 + rhs) + } +} +impl<T: AddressSpace> AddAssign<usize> for VirtualAddress<T> { + #[inline(always)] + fn add_assign(&mut self, rhs: usize) { + // Will panic on overflow + *self = Self::from(self.0 + rhs); + } +} +impl<T: AddressSpace> Sub<usize> for VirtualAddress<T> { + type Output = Self; + + #[inline(always)] + fn sub(self, rhs: usize) -> Self { + // Will panic on underflow + Self::from(self.0 - rhs) + } +} +impl<T: AddressSpace> SubAssign<usize> for VirtualAddress<T> { + #[inline(always)] + fn sub_assign(&mut self, rhs: usize) { + // Will panic on underflow + *self = Self::from(self.0 - rhs); + } +} + +// Trivial conversion VirtualAddress -> PhysicalAddress +impl<T: AddressSpace + TrivialConvert> From<VirtualAddress<T>> for PhysicalAddress { + #[inline(always)] + fn from(virt: VirtualAddress<T>) -> Self { + assert!(virt.0 < T::LIMIT); + PhysicalAddress::from(virt.0 - T::OFFSET) + } +} + +// Formatting +impl<T: AddressSpace> fmt::Debug for VirtualAddress<T> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "<{} {:#018x}>", T::NAME, self.0) + } +} + +impl<T: AddressSpace> VirtualAddress<T> { + #[inline(always)] + pub const fn null() -> Self { + Self(0, PhantomData) + } + + pub fn try_subtract(self, p: usize) -> Option<Self> { + let (res, overflow) = self.0.overflowing_sub(p); + if overflow || res < T::OFFSET || res >= T::LIMIT { + None + } else { + Some(Self(res, PhantomData)) + } + } + + #[inline] + pub fn diff(start: Self, end: Self) -> isize { + if end >= start { + isize::try_from(end.0 - start.0).expect("Address subtraction overflowed") + } else { + -isize::try_from(start.0 - end.0).expect("Address subtraction overflowed") + } + } + + #[inline(always)] + pub fn try_diff(start: Self, end: Self) -> Option<isize> { + if end >= start { + isize::try_from(end.0 - start.0).ok() + } else { + isize::try_from(start.0 - end.0).map(Neg::neg).ok() + } + } + + #[inline(always)] + pub unsafe fn as_slice_mut<U>(self, count: usize) -> &'static mut [U] { + core::slice::from_raw_parts_mut(self.0 as *mut _, count) + } + + #[inline(always)] + pub unsafe fn as_mut<U>(self) -> &'static mut U { + &mut *(self.0 as *mut U) + } +} + +// Step +impl<T: AddressSpace> Step for VirtualAddress<T> { + #[inline] + fn steps_between(_p0: &Self, _p1: &Self) -> Option<usize> { + todo!() + } + + #[inline] + fn forward_checked(p: Self, steps: usize) -> Option<Self> { + p.0.checked_add(steps).map(Self::from) + } + + #[inline] + fn backward_checked(p: Self, steps: usize) -> Option<Self> { + p.0.checked_sub(steps).map(Self::from) + } +} + +// Conversion into VirtualAddress +impl<T: AddressSpace> From<usize> for VirtualAddress<T> { + #[inline(always)] + fn from(p: usize) -> Self { + if T::LIMIT > 0 { + assert!(p >= T::OFFSET && p < T::LIMIT); + } + Self(p, PhantomData) + } +} + +#[cfg(target_pointer_width = "64")] +impl<T: AddressSpace> From<u64> for VirtualAddress<T> { + #[inline(always)] + fn from(p: u64) -> Self { + Self::from(p as usize) + } +} + +// Conversion from VirtualAddress +impl<T: AddressSpace> From<VirtualAddress<T>> for usize { + #[inline(always)] + fn from(p: VirtualAddress<T>) -> Self { + p.0 + } +} + +#[cfg(target_pointer_width = "64")] +impl<T: AddressSpace> From<VirtualAddress<T>> for u64 { + #[inline(always)] + fn from(p: VirtualAddress<T>) -> Self { + p.0 as u64 + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::PhysicalAddress; + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + struct S0; + impl AddressSpace for S0 { + const NAME: &'static str = "S0"; + const OFFSET: usize = 0x8000; + const LIMIT: usize = Self::OFFSET + 0x4000; + } + impl TrivialConvert for S0 {} + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + struct S1; + impl AddressSpace for S1 { + const NAME: &'static str = "S1"; + const OFFSET: usize = 0; + const LIMIT: usize = 0; + } + impl NoTrivialConvert for S1 {} + + #[test] + fn test_trivial_construct_valid() { + for i in 0x8000usize..0xC000 { + VirtualAddress::<S0>::from(i); + } + } + + #[test] + #[should_panic] + fn test_trivial_construct_invalid_0() { + let _v = VirtualAddress::<S0>::from(0x1234usize); + } + + #[test] + #[should_panic] + fn test_trivial_construct_invalid_1() { + let _v = VirtualAddress::<S0>::from(0xD123usize); + } + + #[test] + fn test_trivial_convert() { + let v0 = VirtualAddress::<S0>::from(0x8123usize); + assert_eq!( + PhysicalAddress::from(v0), + PhysicalAddress::from(0x123usize) + ); + } + + #[test] + fn test_add_valid() { + let v0 = VirtualAddress::<S0>::from(0x8100usize); + assert_eq!(VirtualAddress::<S0>::from(0x8223usize), v0 + 0x123usize); + } + + #[test] + #[should_panic] + fn test_add_overflow() { + let v0 = VirtualAddress::<S0>::from(0x8100usize); + let _v = v0 - 0xF123usize; + } + + #[test] + fn test_subtract_valid() { + let v0 = VirtualAddress::<S0>::from(0x8100usize); + assert_eq!(VirtualAddress::<S0>::from(0x8023usize), v0 - 0xDDusize); + } + + #[test] + #[should_panic] + fn test_subtract_overflow() { + let v0 = VirtualAddress::<S0>::from(0x8100usize); + let _v = v0 - 0x1234usize; + } + + #[test] + fn test_try_subtract() { + let v0 = VirtualAddress::<S0>::from(0x8100usize); + assert_eq!(v0.try_subtract(0x1234usize), None); + assert_eq!( + v0.try_subtract(0x12usize), + Some(VirtualAddress::<S0>::from(0x80EEusize)) + ); + } + + #[test] + fn test_add_assign_valid() { + let mut v0 = VirtualAddress::<S0>::from(0x8100usize); + v0 += 0x123usize; + assert_eq!(v0, VirtualAddress::<S0>::from(0x8223usize)); + } + + #[test] + fn test_sub_assign_valid() { + let mut v0 = VirtualAddress::<S0>::from(0x8321usize); + v0 -= 0x123usize; + assert_eq!(v0, VirtualAddress::<S0>::from(0x81FEusize)); + } + + #[test] + #[should_panic] + fn test_sub_assign_overflow() { + let mut v0 = VirtualAddress::<S0>::from(0x8321usize); + v0 -= 0x1234usize; + } + + #[test] + #[should_panic] + fn test_add_assign_overflow() { + let mut v0 = VirtualAddress::<S0>::from(0x8321usize); + v0 += 0xF234usize; + } + + #[test] + fn test_format() { + let v0 = VirtualAddress::<S0>::from(0x8123usize); + assert_eq!(&format!("{:?}", v0), "<S0 0x0000000000008123>"); + } + + #[test] + fn test_diff() { + let v0 = VirtualAddress::<S0>::from(0x8123usize); + let v1 = VirtualAddress::<S0>::from(0x8321usize); + + // Ok + assert_eq!(VirtualAddress::diff(v0, v1), 510); + assert_eq!(VirtualAddress::diff(v1, v0), -510); + assert_eq!(VirtualAddress::diff(v0, v0), 0); + assert_eq!(VirtualAddress::diff(v1, v1), 0); + } + + #[test] + #[should_panic] + fn test_diff_overflow() { + let v0 = VirtualAddress::<S1>::from(0usize); + let v1 = VirtualAddress::<S1>::from(usize::MAX); + + let _v = VirtualAddress::diff(v0, v1); + } + + #[test] + fn test_step() { + let mut count = 0; + for _ in VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize) { + count += 1; + } + assert_eq!(count, 0x300); + + let mut count = 0; + for _ in (VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize)) + .step_by(0x100) + { + count += 1; + } + assert_eq!(count, 3); + + let mut count = 0; + for _ in + (VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize)).rev() + { + count += 1; + } + assert_eq!(count, 0x300); + + let mut count = 0; + for _ in (VirtualAddress::<S0>::from(0x8000usize)..VirtualAddress::<S0>::from(0x8300usize)) + .rev() + .step_by(0x100) + { + count += 1; + } + assert_eq!(count, 3); + } +} diff --git a/error/Cargo.toml b/error/Cargo.toml new file mode 100644 index 0000000..31b8188 --- /dev/null +++ b/error/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "error" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/error/src/lib.rs b/error/src/lib.rs new file mode 100644 index 0000000..4d2f980 --- /dev/null +++ b/error/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] + +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum Errno { + +} diff --git a/etc/aarch64-unknown-none-rpi3b.ld b/etc/aarch64-unknown-none-rpi3b.ld index 2fd06f7..9967e78 100644 --- a/etc/aarch64-unknown-none-rpi3b.ld +++ b/etc/aarch64-unknown-none-rpi3b.ld @@ -7,18 +7,23 @@ SECTIONS { .text : AT(. - KERNEL_OFFSET) ALIGN(4K) { KEEP(*(.text.boot)) - *(.text) + *(.text*) } .rodata : AT(. - KERNEL_OFFSET) ALIGN(4K) { - *(.rodata) + *(.rodata*) } .data : AT(. - KERNEL_OFFSET) ALIGN(4K) { - *(.data) + *(.data*) } .bss : AT(. - KERNEL_OFFSET) ALIGN(4K) { - *(.bss) + *(COMMON) + *(.bss*) + + . = ALIGN(4K); + PROVIDE(__kernel_end = .); + PROVIDE(__kernel_end_phys = . - KERNEL_OFFSET); } } diff --git a/etc/gdbrc b/etc/gdbrc index f697f0f..ad43054 100644 --- a/etc/gdbrc +++ b/etc/gdbrc @@ -1,4 +1,4 @@ -symbol-file target/aarch64-unknown-none-rpi3b/debug/osdev4 +symbol-file target/aarch64-unknown-none-rpi3b/debug/kernel target remote :1234 layout asm layout regs diff --git a/.cargo/config.toml b/kernel/.cargo/config.toml similarity index 55% rename from .cargo/config.toml rename to kernel/.cargo/config.toml index 1e37b56..44d1694 100644 --- a/.cargo/config.toml +++ b/kernel/.cargo/config.toml @@ -2,4 +2,4 @@ build-std = ["core", "compiler_builtins"] [build] -target = "etc/aarch64-unknown-none-rpi3b.json" +target = "../etc/aarch64-unknown-none-rpi3b.json" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml new file mode 100644 index 0000000..0c38770 --- /dev/null +++ b/kernel/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "kernel" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +address = { path = "../address" } +error = { path = "../error" } +spin = "0.9.2" diff --git a/src/main.rs b/kernel/src/arch/exception.rs similarity index 58% rename from src/main.rs rename to kernel/src/arch/exception.rs index efe9507..8880744 100644 --- a/src/main.rs +++ b/kernel/src/arch/exception.rs @@ -1,8 +1,4 @@ -#![feature(global_asm, llvm_asm)] -#![no_std] -#![no_main] - -pub mod boot; +global_asm!(include_str!("vectors.S")); #[repr(C)] struct ExceptionContext { @@ -36,22 +32,3 @@ struct ExceptionContext { extern "C" fn exc_handler(context: ExceptionContext) -> ! { loop {} } - -#[no_mangle] -extern "C" fn kernel_main() -> ! { - unsafe { - let v = *(0x1234 as *mut u64); - } - - loop { - unsafe { - llvm_asm!("wfe"); - } - } -} - -use core::panic::PanicInfo; -#[panic_handler] -fn panic_handler(_pi: &PanicInfo) -> ! { - loop {} -} diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs new file mode 100644 index 0000000..aa4b15a --- /dev/null +++ b/kernel/src/arch/mod.rs @@ -0,0 +1 @@ +pub mod exception; diff --git a/kernel/src/arch/vectors.S b/kernel/src/arch/vectors.S new file mode 100644 index 0000000..175ff95 --- /dev/null +++ b/kernel/src/arch/vectors.S @@ -0,0 +1,75 @@ +.section .rodata +.global el1_vectors +.p2align 7 +el1_vectors: +// Current level with SP_EL0 +vec_el1_sp_el0_sync: + b . +.p2align 7 +vec_el1_sp_el0_irq: + b . +.p2align 7 +vec_el1_sp_el0_fiq: + b . +.p2align 7 +vec_el1_sp_el0_serror: + b . +// Current level with SL_ELx, x > 0 +.p2align 7 +vec_el1_sp_elx_sync: + sub sp, sp, #192 + stp x0, x1, [sp, #0] + stp x2, x3, [sp, #16] + stp x4, x5, [sp, #32] + stp x6, x7, [sp, #48] + stp x8, x9, [sp, #64] + stp x10, x11, [sp, #80] + stp x12, x13, [sp, #96] + stp x14, x15, [sp, #112] + stp x16, x17, [sp, #128] + stp x18, x29, [sp, #144] + stp x30, xzr, [sp, #160] + mrs x0, esr_el1 + mrs x1, far_el1 + stp x0, x1, [sp, #176] + + mov x0, sp + + bl exc_handler + +.p2align 7 +vec_el1_sp_elx_irq: + b . +.p2align 7 +vec_el1_sp_elx_fiq: + b . +.p2align 7 +vec_el1_sp_elx_serror: + b . +// Lower EL, AArch64 +.p2align 7 +vec_el0_aa64_sync: + b . +.p2align 7 +vec_el0_aa64_irq: + b . +.p2align 7 +vec_el0_aa64_fiq: + b . +.p2align 7 +vec_el0_aa64_serror: + b . +// Lower EL, AArch32 +.p2align 7 +vec_el0_aa32_sync: + b . +.p2align 7 +vec_el0_aa32_irq: + b . +.p2align 7 +vec_el0_aa32_fiq: + b . +.p2align 7 +vec_el0_aa32_serror: + b . + diff --git a/src/boot/entry.S b/kernel/src/boot/entry.S similarity index 70% rename from src/boot/entry.S rename to kernel/src/boot/entry.S index e90e405..ba20ba3 100644 --- a/src/boot/entry.S +++ b/kernel/src/boot/entry.S @@ -17,9 +17,9 @@ .set MAIR_EL1_INNER_NC, (4 << 4) .set MAIR_EL1_DEVICE_nGRE, 0 .set MAIR_EL1_DEVICE, 0 - .set TCR_EL1_IPS_48, (5 << 32) .set TCR_EL1_TG1_4K, (2 << 30) +.set CPACR_EL1_FPEN_TRAP_NONE, (3 << 20) .cpu cortex-a57 .section .text.boot @@ -134,89 +134,21 @@ upper_half: // Shoot off the legs msr ttbr0_el1, xzr - adr x0, el1_vectors - msr vbar_el1, x0 + // Disable trapping for FP instructions + mrs x0, cpacr_el1 + orr x0, x0, CPACR_EL1_FPEN_TRAP_NONE + msr cpacr_el1, x0 adr x0, bsp_stack_top mov sp, x0 + adr x0, el1_vectors + msr vbar_el1, x0 + bl kernel_main b . -.section .rodata -.p2align 7 -el1_vectors: -// Current level with SP_EL0 -vec_el1_sp_el0_sync: - b . -.p2align 7 -vec_el1_sp_el0_irq: - b . -.p2align 7 -vec_el1_sp_el0_fiq: - b . -.p2align 7 -vec_el1_sp_el0_serror: - b . -// Current level with SL_ELx, x > 0 -.p2align 7 -vec_el1_sp_elx_sync: - sub sp, sp, #192 - stp x0, x1, [sp, #0] - stp x2, x3, [sp, #16] - stp x4, x5, [sp, #32] - stp x6, x7, [sp, #48] - stp x8, x9, [sp, #64] - stp x10, x11, [sp, #80] - stp x12, x13, [sp, #96] - stp x14, x15, [sp, #112] - stp x16, x17, [sp, #128] - stp x18, x29, [sp, #144] - stp x30, xzr, [sp, #160] - mrs x0, esr_el1 - mrs x1, far_el1 - stp x0, x1, [sp, #176] - - mov x0, sp - - bl exc_handler - -.p2align 7 -vec_el1_sp_elx_irq: - b . -.p2align 7 -vec_el1_sp_elx_fiq: - b . -.p2align 7 -vec_el1_sp_elx_serror: - b . -// Lower EL, AArch64 -.p2align 7 -vec_el0_aa64_sync: - b . -.p2align 7 -vec_el0_aa64_irq: - b . -.p2align 7 -vec_el0_aa64_fiq: - b . -.p2align 7 -vec_el0_aa64_serror: - b . -// Lower EL, AArch32 -.p2align 7 -vec_el0_aa32_sync: - b . -.p2align 7 -vec_el0_aa32_irq: - b . -.p2align 7 -vec_el0_aa32_fiq: - b . -.p2align 7 -vec_el0_aa32_serror: - b . .section .bss .p2align 4 diff --git a/src/boot/mod.rs b/kernel/src/boot/mod.rs similarity index 100% rename from src/boot/mod.rs rename to kernel/src/boot/mod.rs diff --git a/kernel/src/debug.rs b/kernel/src/debug.rs new file mode 100644 index 0000000..b5dd722 --- /dev/null +++ b/kernel/src/debug.rs @@ -0,0 +1,28 @@ +use core::fmt; + +fn uart_send(ch: u8) { + unsafe { + core::ptr::write_volatile(0xFFFFFF803F215040 as *mut u32, ch as u32); + } +} + +struct Uart; + +impl fmt::Write for Uart { + fn write_str(&mut self, s: &str) -> fmt::Result { + for ch in s.bytes() { + uart_send(ch); + } + Ok(()) + } +} + +#[macro_export] +macro_rules! debug { + ($($args:tt)+) => ($crate::debug::debug_fmt(format_args!($($args)+))) +} + +pub fn debug_fmt(args: fmt::Arguments<'_>) { + use fmt::Write; + write!(Uart {}, "{}", args).unwrap(); +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs new file mode 100644 index 0000000..738ce69 --- /dev/null +++ b/kernel/src/main.rs @@ -0,0 +1,61 @@ +#![feature(global_asm, llvm_asm, const_panic)] +#![no_std] +#![no_main] + +#[macro_use] +pub mod debug; + +pub mod arch; +pub mod boot; +pub mod mem; + +pub use mem::KernelSpace; + +use core::fmt::{self, Write}; + +use address::PhysicalAddress; +use mem::phys::UsableMemory; +#[derive(Clone)] +struct SimpleMemoryIterator<'a> { + inner: Option<&'a UsableMemory>, +} +impl Iterator for SimpleMemoryIterator<'_> { + type Item = UsableMemory; + fn next(&mut self) -> Option<Self::Item> { + if let Some(item) = self.inner { + self.inner = None; + Some(item.clone()) + } else { + None + } + } +} + +#[no_mangle] +extern "C" fn kernel_main() -> ! { + // TODO determine VC/ARM split + let memory = UsableMemory { + start: PhysicalAddress::from(0usize), + end: PhysicalAddress::from(0x30000000usize), + }; + let iter = SimpleMemoryIterator { + inner: Some(&memory), + }; + unsafe { + mem::phys::initialize(iter); + } + + loop { + unsafe { + llvm_asm!("wfe"); + } + } +} + +use core::panic::PanicInfo; +#[panic_handler] +fn panic_handler(pi: &PanicInfo) -> ! { + debug!("PANIC: {:?}\n", pi); + + loop {} +} diff --git a/kernel/src/mem/address.rs b/kernel/src/mem/address.rs new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/mem/mod.rs b/kernel/src/mem/mod.rs new file mode 100644 index 0000000..1765a8d --- /dev/null +++ b/kernel/src/mem/mod.rs @@ -0,0 +1,21 @@ +use address::{AddressSpace, PhysicalAddress, TrivialConvert}; + +pub mod phys; + +#[derive(Copy, Clone, PartialEq, PartialOrd)] +pub struct KernelSpace; +impl AddressSpace for KernelSpace { + const NAME: &'static str = "kernel"; + const OFFSET: usize = 0xFFFFFF8000000000; + const LIMIT: usize = 0xFFFFFF8000000000 + (2 << 30); +} +impl TrivialConvert for KernelSpace {} + +pub const PAGE_SIZE: usize = 0x1000; + +pub fn kernel_end_phys() -> PhysicalAddress { + extern "C" { + static __kernel_end_phys: u8; + } + PhysicalAddress::from(unsafe { &__kernel_end_phys } as *const _ as usize) +} diff --git a/kernel/src/mem/phys/manager.rs b/kernel/src/mem/phys/manager.rs new file mode 100644 index 0000000..d0f4c46 --- /dev/null +++ b/kernel/src/mem/phys/manager.rs @@ -0,0 +1,62 @@ +use super::{PageInfo, PageUsage}; +use crate::KernelSpace; +use address::{PhysicalAddress, VirtualAddress}; +use core::mem::{self, MaybeUninit}; +use error::Errno; +use spin::Mutex; + +pub unsafe trait Manager { + fn alloc_page(&mut self) -> Result<PhysicalAddress, Errno>; + fn alloc_contiguous_pages(&mut self, count: usize) -> Result<PhysicalAddress, Errno>; + fn free_page(&mut self, page: PhysicalAddress) -> Result<(), Errno>; + + // TODO status() +} + +pub struct SimpleManager { + pages: &'static mut [Mutex<PageInfo>], +} + +impl SimpleManager { + pub(super) unsafe fn initialize(at: PhysicalAddress, count: usize) -> Self { + let pages: &'static mut [Mutex<PageInfo>] = + VirtualAddress::<KernelSpace>::from(at).as_slice_mut(count); + + // Initialize uninit pages + for index in 0..count { + mem::forget(mem::replace( + &mut pages[index], + Mutex::new(PageInfo { + refcount: 0, + usage: PageUsage::Reserved, + }), + )); + } + + Self { pages } + } + + pub(super) unsafe fn add_page(&mut self, addr: PhysicalAddress) { + let mut page = self.pages[addr.page_index()].lock(); + assert!(page.refcount == 0 && page.usage == PageUsage::Reserved); + page.usage = PageUsage::Available; + + // Fill the page with trash + let slice: &mut [u8; 4096] = VirtualAddress::<KernelSpace>::from(addr).as_mut(); + slice.fill(0); + } +} + +unsafe impl Manager for SimpleManager { + fn alloc_page(&mut self) -> Result<PhysicalAddress, Errno> { + todo!() + } + fn alloc_contiguous_pages(&mut self, _count: usize) -> Result<PhysicalAddress, Errno> { + todo!() + } + fn free_page(&mut self, _page: PhysicalAddress) -> Result<(), Errno> { + todo!() + } +} + +pub(super) static MANAGER: Mutex<Option<SimpleManager>> = Mutex::new(None); diff --git a/kernel/src/mem/phys/mod.rs b/kernel/src/mem/phys/mod.rs new file mode 100644 index 0000000..8fa55eb --- /dev/null +++ b/kernel/src/mem/phys/mod.rs @@ -0,0 +1,118 @@ +use super::PAGE_SIZE; +use address::PhysicalAddress; +use core::convert::TryFrom; +use core::mem::size_of; +use error::Errno; +use spin::Mutex; + +mod manager; +use manager::{Manager, SimpleManager, MANAGER}; +mod reserved; +pub use reserved::ReservedRegion; +mod pbox; +pub use pbox::PhysBox; + +type ManagerImpl = SimpleManager; + +#[derive(PartialEq, Debug)] +pub enum PageUsage { + Reserved, + Available, + Kernel, +} + +pub struct PageInfo { + refcount: usize, + usage: PageUsage, +} + +#[derive(Clone)] +pub struct UsableMemory { + pub start: PhysicalAddress, + pub end: PhysicalAddress, +} + +const MAX_PAGES: usize = 1024; + +pub fn alloc_page() -> Result<PhysicalAddress, Errno> { + MANAGER.lock().as_mut().unwrap().alloc_page() +} + +pub fn alloc_contiguous_pages(count: usize) -> Result<PhysicalAddress, Errno> { + MANAGER + .lock() + .as_mut() + .unwrap() + .alloc_contiguous_pages(count) +} + +pub fn free_page(page: PhysicalAddress) -> Result<(), Errno> { + MANAGER.lock().as_mut().unwrap().free_page(page) +} + +fn find_contiguous<T: Iterator<Item = UsableMemory>>( + iter: T, + count: usize, +) -> Option<PhysicalAddress> { + for region in iter { + let mut collected = 0; + let mut base_addr = None; + + for addr in (region.start..region.end).step_by(PAGE_SIZE) { + if reserved::is_reserved(addr) { + collected = 0; + base_addr = None; + continue; + } + + if base_addr.is_none() { + base_addr = Some(addr); + } + collected += 1; + if collected == count { + return base_addr; + } + } + } + + None +} + +pub unsafe fn initialize<T: Iterator<Item = UsableMemory> + Clone>(iter: T) { + // Step 1. Count available memory + let mut total_pages = 0usize; + for reg in iter.clone() { + total_pages += + usize::try_from(PhysicalAddress::diff(reg.start, reg.end)).unwrap() / PAGE_SIZE; + } + // TODO maybe instead of size_of::<...> use Layout? + let need_pages = ((total_pages * size_of::<Mutex<PageInfo>>()) + 0xFFF) / 0x1000; + + reserved::reserve_kernel(); + + // Step 2. Allocate memory for page array + let pages_base = + find_contiguous(iter.clone(), need_pages).expect("Failed to allocate memory for page info"); + + reserved::reserve_pages(pages_base, need_pages); + + // Step 3. Initialize the memory manager with available pages + let mut manager = ManagerImpl::initialize(pages_base, total_pages); + + let mut usable_pages = 0usize; + 'l0: for region in iter { + for addr in (region.start..region.end).step_by(PAGE_SIZE) { + if !reserved::is_reserved(addr) { + manager.add_page(addr); + usable_pages += 1; + if usable_pages == MAX_PAGES { + break 'l0; + } + } + } + } + + debug!("{}K of usable physical memory\n", usable_pages * 4); + + *MANAGER.lock() = Some(manager); +} diff --git a/kernel/src/mem/phys/pbox.rs b/kernel/src/mem/phys/pbox.rs new file mode 100644 index 0000000..4dcc8ad --- /dev/null +++ b/kernel/src/mem/phys/pbox.rs @@ -0,0 +1,24 @@ +use address::PhysicalAddress; +use error::Errno; + +pub struct PhysBox { + base: PhysicalAddress, + count: usize, +} + +impl PhysBox { + pub fn new() -> Result<Self, Errno> { + Ok(Self { + base: super::alloc_page()?, + count: 1 + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + for p in 0..self.count { + super::free_page(self.base + p * 0x1000).unwrap(); + } + } +} diff --git a/kernel/src/mem/phys/reserved.rs b/kernel/src/mem/phys/reserved.rs new file mode 100644 index 0000000..9db375d --- /dev/null +++ b/kernel/src/mem/phys/reserved.rs @@ -0,0 +1,79 @@ +use crate::mem::{kernel_end_phys, PAGE_SIZE}; +use address::PhysicalAddress; +use core::mem::MaybeUninit; +use core::ptr::null_mut; + +pub struct ReservedRegion { + pub start: PhysicalAddress, + pub end: PhysicalAddress, + next: *mut ReservedRegion, +} + +pub struct ReservedRegionIterator { + ptr: *mut ReservedRegion, +} + +impl Iterator for ReservedRegionIterator { + type Item = &'static mut ReservedRegion; + + fn next(&mut self) -> Option<Self::Item> { + if let Some(item) = unsafe { self.ptr.as_mut() } { + self.ptr = item.next; + Some(item) + } else { + None + } + } +} + +impl ReservedRegion { + pub const fn new(start: PhysicalAddress, end: PhysicalAddress) -> ReservedRegion { + assert!(start.is_paligned() && end.is_paligned()); + ReservedRegion { + start, + end, + next: null_mut() + } + } +} + +static mut RESERVED_REGIONS_HEAD: *mut ReservedRegion = null_mut(); +static mut RESERVED_REGION_KERNEL: MaybeUninit<ReservedRegion> = MaybeUninit::uninit(); +static mut RESERVED_REGION_PAGES: MaybeUninit<ReservedRegion> = MaybeUninit::uninit(); + +pub unsafe fn reserve(region: *mut ReservedRegion) { + (*region).next = RESERVED_REGIONS_HEAD; + RESERVED_REGIONS_HEAD = region; +} + +pub(super) unsafe fn reserve_kernel() { + RESERVED_REGION_KERNEL.write(ReservedRegion::new( + PhysicalAddress::from(0usize), + kernel_end_phys(), + )); + reserve(RESERVED_REGION_KERNEL.as_mut_ptr()); +} + +pub(super) unsafe fn reserve_pages(base: PhysicalAddress, count: usize) { + RESERVED_REGION_PAGES.write(ReservedRegion::new( + base, + base + count * PAGE_SIZE + )); + reserve(RESERVED_REGION_PAGES.as_mut_ptr()); +} + +pub fn is_reserved(page: PhysicalAddress) -> bool { + unsafe { + let mut iter = RESERVED_REGIONS_HEAD; + while !iter.is_null() { + let region = &*iter; + + if page >= region.start && page < region.end { + return true; + } + + iter = region.next; + } + } + false +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e69de29