aboutsummaryrefslogtreecommitdiff
path: root/src/util/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/mem')
-rw-r--r--src/util/mem/alloc.rs289
-rw-r--r--src/util/mem/mod.rs13
-rw-r--r--src/util/mem/paging.rs93
-rw-r--r--src/util/mem/types.rs54
4 files changed, 449 insertions, 0 deletions
diff --git a/src/util/mem/alloc.rs b/src/util/mem/alloc.rs
new file mode 100644
index 0000000..dfe8c60
--- /dev/null
+++ b/src/util/mem/alloc.rs
@@ -0,0 +1,289 @@
+//! # Allocate crate
+//!
+//! Provides the Global allocator and methods
+//! to create special purpose allocators.
+use super::types::*;
+use crate::lib::lifo_queue::init_lifo_queue;
+use crate::lib::lifo_queue::LifoQueue;
+use crate::lib::node::Node;
+use crate::lib::queue::Queue;
+use crate::lib::sync::interface::Mutex;
+use crate::lib::sync::NullLock;
+use crate::serial_vprintln;
+use crate::util::mem::{GlobalAlloc, Layout};
+
+/// # Grand Allocator
+///
+/// The structure that uses different sized pools and allocates memory chunks
+pub struct GrandAllocator {}
+
+/// # The number of elements of each size
+const GRAND_ALLOC_SIZE: usize = 64;
+
+init_lifo_queue!(U8_GRAND_ALLOC, GRAND_ALLOC_SIZE, 0, u8);
+init_lifo_queue!(U16_GRAND_ALLOC, GRAND_ALLOC_SIZE, 0, u16);
+init_lifo_queue!(U32_GRAND_ALLOC, GRAND_ALLOC_SIZE, 0, u32);
+init_lifo_queue!(U64_GRAND_ALLOC, GRAND_ALLOC_SIZE, 0, u64);
+init_lifo_queue!(U128_GRAND_ALLOC, GRAND_ALLOC_SIZE, 0, u128);
+init_lifo_queue!(U256_GRAND_ALLOC, GRAND_ALLOC_SIZE, { U256::new() }, U256);
+init_lifo_queue!(U512_GRAND_ALLOC, GRAND_ALLOC_SIZE, { U512::new() }, U512);
+init_lifo_queue!(U1024_GRAND_ALLOC, GRAND_ALLOC_SIZE, { U1024::new() }, U1024);
+init_lifo_queue!(U2048_GRAND_ALLOC, GRAND_ALLOC_SIZE, { U2048::new() }, U2048);
+init_lifo_queue!(U4096_GRAND_ALLOC, GRAND_ALLOC_SIZE, { U4096::new() }, U4096);
+
+impl GrandAllocator {
+ pub fn init(&self) -> Result<(), &'static str> {
+ serial_vprintln!("GA: \x1b[93mInit U8 Pool\x1b[0m");
+ U8_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U16 Pool\x1b[0m");
+ U16_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U32 Pool\x1b[0m");
+ U32_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U64 Pool\x1b[0m");
+ U64_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U128 Pool\x1b[0m");
+ U128_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U256 Pool\x1b[0m");
+ U256_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U512 Pool\x1b[0m");
+ U512_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U1024 Pool\x1b[0m");
+ U1024_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U2048 Pool\x1b[0m");
+ U2048_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[93mInit U4096 Pool\x1b[0m");
+ U4096_GRAND_ALLOC.init();
+ serial_vprintln!("GA: \x1b[94mPools Initialized!\x1b[0m");
+ Ok(())
+ }
+}
+
+unsafe impl GlobalAlloc for GrandAllocator {
+ /// # Allocator
+ ///
+ /// Allocate the fixed size chunks
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ serial_vprintln!("GA: Allocating chunk of size {}!", layout.size());
+ match layout.size() {
+ 1 => match U8_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 2 => match U16_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 3..=4 => match U32_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 5..=8 => match U64_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 9..=16 => match U128_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 17..=32 => match U256_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 33..=64 => match U512_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 65..=128 => match U1024_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 129..=256 => match U2048_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ 257..=512 => match U4096_GRAND_ALLOC.pop() {
+ None => {
+ panic!("No cells to allocate!");
+ }
+ Some(elem) => {
+ return (*elem).ptr();
+ }
+ },
+ _ => {
+ panic!("No allocators for size {}!", layout.size());
+ }
+ }
+ }
+
+ /// # Deallocate
+ ///
+ /// Deallocate the fixed size chunks by searching for them
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ serial_vprintln!("GA: Deallocating chunk of size {}!", layout.size());
+ match layout.size() {
+ 1 => {
+ U8_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U8_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 2 => {
+ U16_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U16_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 3..=4 => {
+ U32_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U32_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 5..=8 => {
+ U64_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U64_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 9..=16 => {
+ U128_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U128_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 17..=32 => {
+ U256_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U256_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 33..=64 => {
+ U512_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U512_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 65..=128 => {
+ U1024_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U1024_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 129..=256 => {
+ U2048_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U2048_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ 257..=512 => {
+ U4096_GRAND_ALLOC.inner.lock(|pool| {
+ let spacing: usize = (pool[2].ptr() as usize) - (pool[1].ptr() as usize);
+ let diff: usize = (ptr as usize) - (pool[1].ptr() as usize);
+ let index: usize = diff/spacing;
+ assert!(index < GRAND_ALLOC_SIZE, "{} is out of the allocation bounds ({})", index, GRAND_ALLOC_SIZE);
+ assert_eq!(diff % spacing, 0, "{} is not aligned with the spacings and so it must not have been allocated by the Grand Allocator", diff % spacing);
+ U4096_GRAND_ALLOC.push(&mut pool[index+1]);
+ serial_vprintln!("GA: Freeing ({}, {}, {})", index, diff, spacing);
+ });
+ }
+ _ => {
+ panic!("No deallocators for size {}!", layout.size());
+ }
+ }
+ }
+}
+
+/// # Grand Allocator
+///
+/// The allocator of allocators. It hands out fixed sized memory chunks.
+#[global_allocator]
+pub static ALLOCATOR: GrandAllocator = GrandAllocator {};
+
+/// # Global Allocator
+///
+/// Returns a borrow for the Global Allocator
+pub fn allocator() -> &'static crate::util::mem::alloc::GrandAllocator {
+ serial_vprintln!("AL: Getting global allocator!");
+ &crate::util::mem::alloc::ALLOCATOR
+}
diff --git a/src/util/mem/mod.rs b/src/util/mem/mod.rs
new file mode 100644
index 0000000..36c02a2
--- /dev/null
+++ b/src/util/mem/mod.rs
@@ -0,0 +1,13 @@
+//! # Memory crate
+//!
+//! Provides the Allocator for the OS.
+pub mod alloc;
+mod paging;
+mod types;
+pub use paging::*;
+
+extern crate alloc as core_alloc;
+pub use core_alloc::alloc::{GlobalAlloc, Layout};
+pub use core_alloc::boxed::Box;
+pub use core_alloc::format;
+pub use core_alloc::string::String;
diff --git a/src/util/mem/paging.rs b/src/util/mem/paging.rs
new file mode 100644
index 0000000..8a21bda
--- /dev/null
+++ b/src/util/mem/paging.rs
@@ -0,0 +1,93 @@
+//! # MMU Functions
+
+pub mod MMU {
+ pub const CACHABLE: u32 = 1 << 3;
+ pub const BUFFERABLE: u32 = 1 << 2;
+ pub const NO_PERMISSIONS_REQUIRED: u32 = 0b11 << 10;
+ pub const PERMISSIONS_REQUIRED: u32 = 0b01 << 10;
+ pub const BASE: u32 = 0x0004000;
+ pub const MASK: u32 = 0x1005;
+}
+
+/// # Start
+pub fn mmu_start(init: u32, mask: u32) {
+ unsafe {
+ core::arch::asm!("mov r2, #0
+ // Invalidate Caches
+ mcr p15,0,r2,c7,c1,6
+ // Invalidate TLB entries
+ mcr p15,0,r2,c8,c7,0
+ // Data synchronisation barrier
+ dsb
+
+ // Set all domains to 0b11
+ mvn r2, #0
+ bic r2, #0xC
+ mcr p15,0,r2,c3,c0,0
+
+ // Set the translation table base address (remember to align 16 KiB!)
+ mcr p15,0,r0,c2,c0,0
+ mcr p15,0,r0,c2,c0,1
+ mov r3, #0
+ mcr p15,0,r3,c2,c0,2
+
+ // Set the bits mentioned above
+ mrc p15,0,r2,c1,c0,0
+ orr r2,r2,r1
+ mcr p15,0,r2,c1,c0,0", in("r0") init, in("r1") mask);
+ }
+}
+
+/// # Stop
+pub fn mmu_stop() {
+ unsafe {
+ core::arch::asm!(
+ "mrc p15,0,r2,c1,c0,0
+ bic r2,#0x1000
+ bic r2,#0x0004
+ bic r2,#0x0001
+ mcr p15,0,r2,c1,c0,0"
+ );
+ }
+}
+
+pub fn tlb_invalidate() {
+ unsafe {
+ core::arch::asm!(
+ "mov r2, #0
+ // Invalidate Entries
+ mcr p15, 0, r2, c8, c7, 0
+ // DSB
+ mcr p15, 0, r2, c7, c10, 4"
+ );
+ }
+}
+
+pub fn mmu_section(virt: u32, phys: u32, flags: u32) {
+ use crate::cpu::store32;
+ let offset: u32 = virt >> 20;
+ let entry: u32 = MMU::BASE | (offset << 2);
+ let physv: u32 = (phys & 0xFFF00000) | (flags & 0x7FFC) | 0x00C02;
+ store32(entry, physv)
+}
+
+pub fn mmu_init() {
+ let mut addr: u32 = 0;
+ loop {
+ mmu_section(
+ addr,
+ addr,
+ MMU::CACHABLE | MMU::BUFFERABLE | MMU::NO_PERMISSIONS_REQUIRED,
+ );
+ if addr == 0xFFF00000 {
+ break;
+ }
+ addr += 0x00100000;
+ }
+ mmu_section(
+ 0x3F200000,
+ 0x3F200000,
+ MMU::CACHABLE | MMU::BUFFERABLE | MMU::PERMISSIONS_REQUIRED,
+ );
+ mmu_start(MMU::BASE, MMU::MASK);
+}
diff --git a/src/util/mem/types.rs b/src/util/mem/types.rs
new file mode 100644
index 0000000..ed22132
--- /dev/null
+++ b/src/util/mem/types.rs
@@ -0,0 +1,54 @@
+/// # u256 struct
+///
+/// 256 bit size field
+#[derive(Copy, Clone)]
+pub struct U256(u128, u128);
+impl U256 {
+ pub const fn new() -> Self {
+ U256(0, 0)
+ }
+}
+
+/// # u512 struct
+///
+/// 512 bit size field
+#[derive(Copy, Clone)]
+pub struct U512(U256, U256);
+impl U512 {
+ pub const fn new() -> Self {
+ U512(U256::new(), U256::new())
+ }
+}
+
+/// # u1024 struct
+///
+/// 1024 bit size field
+#[derive(Copy, Clone)]
+pub struct U1024(U512, U512);
+impl U1024 {
+ pub const fn new() -> Self {
+ U1024(U512::new(), U512::new())
+ }
+}
+
+/// # u2048 struct
+///
+/// 2048 bit size field
+#[derive(Copy, Clone)]
+pub struct U2048(U1024, U1024);
+impl U2048 {
+ pub const fn new() -> Self {
+ U2048(U1024::new(), U1024::new())
+ }
+}
+
+/// # u4096 struct
+///
+/// 4096 bit size field
+#[derive(Copy, Clone)]
+pub struct U4096(U2048, U2048);
+impl U4096 {
+ pub const fn new() -> Self {
+ U4096(U2048::new(), U2048::new())
+ }
+}