diff options
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/fifo_queue.rs | 191 | ||||
| -rw-r--r-- | src/util/mem/alloc.rs | 289 | ||||
| -rw-r--r-- | src/util/mem/mod.rs | 13 | ||||
| -rw-r--r-- | src/util/mem/paging.rs | 93 | ||||
| -rw-r--r-- | src/util/mem/types.rs | 54 | ||||
| -rw-r--r-- | src/util/mod.rs | 3 | ||||
| -rw-r--r-- | src/util/panic_wait.rs | 45 | ||||
| -rw-r--r-- | src/util/print.rs | 56 | 
8 files changed, 553 insertions, 191 deletions
| diff --git a/src/util/fifo_queue.rs b/src/util/fifo_queue.rs deleted file mode 100644 index 6748ab4..0000000 --- a/src/util/fifo_queue.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! # FIFO Queue -//! -//! Provides the FIFO queue structure for allocations -use crate::sync::interface::Mutex; -use crate::sync::NullLock; -use crate::serial_vprintln; -use core::fmt; -use core::fmt::{Debug, Formatter}; - -/// # Initialize Queue -/// - Name: Symbol name -/// - Size: Number of elements -/// - Default: Default value -/// - Type: Data Type -#[macro_export] -macro_rules! init_queue { -	($name:tt,$size:tt,$default:tt,$type:ty) => { -		init_queue!{@gen [$name,$size,$default,$type,concat!("# ", stringify!($type), " Queue Allocator")]} -	}; -	(@gen [$name:tt,$size:tt,$default:tt,$type:ty,$doc:expr]) => { -		#[doc = $doc] -		#[link_section = ".data.alloc"] -		pub static $name: QueueAllocator<'static, $type, {$size+2}> = QueueAllocator::<$type, {$size+2}>{inner: NullLock::new([QueueItem::new($default); {$size+2}])}; -	}; -} - -#[derive(Copy, Clone)] -/// # Queue Item -/// -/// Encapsulates a data element and a pointer to -/// the next `Queue` item -pub struct QueueItem<'a, T: Sized> { -    /// # Data -    /// -    /// The encapsulated data -    data: T, -    /// # Pointer to the next item -    /// -    /// Stores either `None` or points -    /// to the next item. -    next: Option<*mut QueueItem<'a, T>>, -} - -impl<T> QueueItem<'_, T> { -    /// # Constructor -    pub const fn new(data: T) -> Self { -        Self { -            data: data, -            next: None, -        } -    } -    /// # Get the inner data -    /// -    /// Returns a borrow of the underlying data. -    pub fn inner(&mut self) -> &mut T { -        &mut self.data -    } -    /// # Get pointer to inner data -    pub fn ptr(&mut self) -> *mut u8 { -        self.inner() as *mut T as *mut u8 -    } -} - -/// # Sharing Thread Safety for QueueItem -unsafe impl<T> Send for QueueItem<'_, T> {} - -impl<T: Debug> Debug for QueueItem<'_, T> { -    /// # Debug formatter for `QueueItem` -    /// -    /// Output the encapsulated data -    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { -        #[cfg(feature = "verbose")] -        return write!( -            f, -            "{:?} {:x} {:?}", -            self.data, self as *const QueueItem<'_, T> as usize, self.next -        ); - -        #[cfg(not(feature = "verbose"))] -        return write!(f, "{:?}", self.data); -    } -} - -/// # Queue Allocator -/// -/// Structure to store a pool of allocated data structures. -pub struct QueueAllocator<'a, T: Sized, const COUNT: usize> { -    /// # Synchronized Pool of items -    /// -    /// Stores synchronization wrapper around the data pool -    pub inner: NullLock<[QueueItem<'a, T>; COUNT]>, -} - -/// # Sharing Thread Safety for QueueAllocator -unsafe impl<T, const COUNT: usize> Send for QueueAllocator<'_, T, COUNT> {} - -impl<'a, T: Sized, const COUNT: usize> QueueAllocator<'a, T, COUNT> { -    /// # Initialization of Fixed-Size Pool -    /// -    /// Establishes the header and footer of the queue -    /// as the first and second elements respectively. -    /// All of the internal elements point to the next -    /// one and the final element points to `None` -    pub fn init(&self) { -        serial_vprintln!("QA: Initializing Queue Allocator!"); -        self.inner.lock(|queue| { -            serial_vprintln!("QA: Clearing internal references..."); -            for idx in 2..COUNT { -                if idx != COUNT - 1 { -                    queue[idx].next = Some(&mut queue[idx + 1] as *mut QueueItem<'a, T>); -                } else { -                    queue[idx].next = None; -                } -            } -            serial_vprintln!("QA: Initializing head and tail..."); -            queue[0].next = Some(&mut queue[2] as *mut QueueItem<'a, T>); -            queue[1].next = Some(&mut queue[COUNT - 1] as *mut QueueItem<'a, T>); -        }); -        serial_vprintln!("QA: Initialized Queue Allocator!"); -    } - -    /// # Allocate Data -    /// -    /// If there is a data chunk available, -    /// return it, otherwise return `None` -    #[allow(dead_code)] -    pub fn alloc(&self) -> Option<&mut QueueItem<'a, T>> { -        serial_vprintln!("QA: Allocating chunk!"); -        return self.inner.lock(|pool| { -            if let Some(entry) = pool[0].next { -                serial_vprintln!("QA: Found chunk!"); -                pool[0].next = unsafe { (*entry).next }; -                unsafe { -                    (*entry).next = None; -                } -                match pool[0].next { -                    None => pool[1].next = None, -                    _ => {} -                } -                serial_vprintln!("QA: \x1b[92mAllocated {:x}\x1b[0m", unsafe { -                    (*entry).ptr() as usize -                }); -                return Some(unsafe { &mut *entry as &mut QueueItem<'a, T> }); -            } else { -                serial_vprintln!("QA: No chunks available!"); -                return None; -            } -        }); -    } - -    /// # Free -    /// -    /// Add the item to the end of the queue. -    /// If there were no items, set it as the head. -    #[allow(dead_code)] -    pub fn free(&self, freed_item: &mut QueueItem<'a, T>) { -        serial_vprintln!("QA: Deallocating chunk!"); -        self.inner.lock(|pool| { -            freed_item.next = None; -            match pool[1].next { -                None => { -                    pool[0].next = Some(freed_item as *mut QueueItem<'a, T>); -                } -                Some(entry) => unsafe { -                    (*entry).next = Some(freed_item as *mut QueueItem<'a, T>); -                }, -            } -            pool[1].next = Some(freed_item as *mut QueueItem<'a, T>); -            serial_vprintln!( -                "QA: \x1b[91mDeallocated {:x}\x1b[0m", -                freed_item.ptr() as usize -            ); -        }); -    } -} - -impl<T: Debug, const COUNT: usize> Debug for QueueAllocator<'_, T, COUNT> { -    /// # Debug Formatted Output -    /// -    /// Output each data point in the array with -    /// its debug formatter. -    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { -        self.inner.lock(|queue| { -            #[cfg(feature = "verbose")] -            return write!(f, "{:?}", queue); - -            #[cfg(not(feature = "verbose"))] -            return write!(f, "{:?}", queue); -        }) -    } -} 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()) +    } +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..d33f520 --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1,3 @@ +pub mod mem; +pub mod panic_wait; +pub mod print; diff --git a/src/util/panic_wait.rs b/src/util/panic_wait.rs new file mode 100644 index 0000000..a8d0962 --- /dev/null +++ b/src/util/panic_wait.rs @@ -0,0 +1,45 @@ +//! # Panic module +//! +//! A panic handler that infinitely waits + +use crate::{cpu, serial_println}; +use core::panic::PanicInfo; + +/// # Prevent Double Faulting +/// +/// An atomic operation is used to mark that +/// a fault has occurred. If it detects that +/// there was already a fault, it spins to +/// prevent a recursive faulting cycle. +fn panic_prevent_reenter() { +    use core::sync::atomic::{AtomicBool, Ordering}; + +    static PANIC_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + +    if !PANIC_IN_PROGRESS.load(Ordering::Relaxed) { +        PANIC_IN_PROGRESS.store(true, Ordering::Relaxed); +        return; +    } + +    cpu::wait_forever() +} + +/// # Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { +    panic_prevent_reenter(); + +    let (location, line, column) = match info.location() { +        Some(loc) => (loc.file(), loc.line(), loc.column()), +        _ => ("???", 0, 0), +    }; + +    serial_println!( +        "Kernel panic!\n\nPanic Location:\n\tFile: '{}', line {}, column {}\n\n{}", +        location, +        line, +        column, +        info.message().unwrap_or(&format_args!("")), +    ); +    cpu::wait_forever() +} diff --git a/src/util/print.rs b/src/util/print.rs new file mode 100644 index 0000000..34e808c --- /dev/null +++ b/src/util/print.rs @@ -0,0 +1,56 @@ +//! # Printing to UART +//! +//! This module contains the macros to print formatted strings to UART. +use crate::bsp::drivers::uart::UART_WRITER; +use crate::lib::console::interface::Write; +use core::fmt; + +#[doc(hidden)] +pub fn _serial_print(args: fmt::Arguments) { +    UART_WRITER.write_fmt(args).unwrap(); +} + +/// # Print without newline +/// +/// Print formatted arguments without a newline +#[macro_export] +macro_rules! serial_print { +	($($arg:tt)*) => ($crate::util::print::_serial_print(format_args!($($arg)*))); +} + +/// # Print with newline +/// +/// Print formatted arguments with a newline +#[macro_export] +macro_rules! serial_println { +	() => ($crate::serial_print!("\n")); +	($($arg:tt)*) => ({ +		$crate::util::print::_serial_print(format_args_nl!($($arg)*)); +	}) +} + +/// # Debug print without newline +/// +/// Print formatted arguments without a newline but only with `verbose` feature +#[macro_export] +macro_rules! serial_vprint { +	($($arg:tt)*) => ({ +		#[cfg(feature="verbose")] +		$crate::util::print::_serial_print(format_args!($($arg)*)) +	}); +} + +/// # Debug print with newline +/// +/// Print formatted arguments with a newline but only with `verbose` feature +#[macro_export] +macro_rules! serial_vprintln { +	() => ({ +		#[cfg(feature="verbose")] +		$crate::serial_print!("\n") +	}); +	($($arg:tt)*) => ({ +		#[cfg(feature="verbose")] +		$crate::util::print::_serial_print(format_args_nl!($($arg)*)); +	}) +} | 
