diff --git a/.vscode/settings.json b/.vscode/settings.json index 488981a..4c0673a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,4 +7,5 @@ "./kernel-lib/Cargo.toml", "./common/Cargo.toml", ], + "editor.formatOnSave": true, } \ No newline at end of file diff --git a/Makefile b/Makefile index d71aad0..36e9d8b 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ disk.img: bootloader/target/x86_64-unknown-uefi/$(PROFILE)/bootloader.efi kernel install: bootloader/target/x86_64-unknown-uefi/$(PROFILE)/bootloader.efi kernel/target/x86_64-lemolaos-eabi/$(PROFILE)/kernel.elf mkdir -p mnt && \ - sudo mount -t drvfs e: mnt && \ + sudo mount -t drvfs d: mnt && \ sudo mkdir -p mnt/EFI/BOOT && \ sudo cp bootloader/target/x86_64-unknown-uefi/$(PROFILE)/bootloader.efi mnt/EFI/BOOT/BOOTX64.EFI && \ sudo cp kernel/target/x86_64-lemolaos-eabi/$(PROFILE)/kernel.elf mnt/kernel.elf && \ diff --git a/bootloader/Cargo.lock b/bootloader/Cargo.lock index 9b9e496..60f72f9 100644 --- a/bootloader/Cargo.lock +++ b/bootloader/Cargo.lock @@ -25,6 +25,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bootloader" version = "0.1.0" @@ -47,6 +53,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "common" version = "0.1.0" +dependencies = [ + "uefi-raw", +] [[package]] name = "elf" @@ -120,6 +129,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.21" @@ -161,7 +190,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1681124c58206560962ed40f54603f0f8364dc4ee747b4f5adb8edf2f48a00d5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "log", "ucs2", "uefi-macros", @@ -178,6 +207,17 @@ dependencies = [ "syn", ] +[[package]] +name = "uefi-raw" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7" +dependencies = [ + "bitflags 2.4.1", + "ptr_meta", + "uguid", +] + [[package]] name = "uefi-services" version = "0.14.0" @@ -189,6 +229,12 @@ dependencies = [ "uefi", ] +[[package]] +name = "uguid" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5" + [[package]] name = "unicode-ident" version = "1.0.5" diff --git a/bootloader/src/main.rs b/bootloader/src/main.rs index d851ae0..b338a8b 100644 --- a/bootloader/src/main.rs +++ b/bootloader/src/main.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::vec::Vec; use alloc::{string::String, vec}; -use common::types::{GraphicsInfo, KernelMain, KernelMainArg, PixcelFormat}; +use common::types::{GraphicsInfo, KernelMain, KernelMainArg, MemMapEntry, PixcelFormat}; use core::arch::asm; use core::panic; use elf::{endian::AnyEndian, ElfBytes}; @@ -200,15 +200,28 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { unsafe { dont_use_this_uninit_buf.set_len(buf_size) }; - let (_system_table, _memory_map) = + let mut mem_map_buf = Vec::::with_capacity(buf_size); + let (_system_table, memory_map) = match system_table.exit_boot_services(image_handle, &mut dont_use_this_uninit_buf) { Ok(ret) => ret, Err(err) => { panic!("Failed to exit_boot_services, {:?}", err); } }; + let size = memory_map.len(); + { + let header = mem_map_buf.as_mut_ptr() as *mut MemMapEntry; + unsafe { (*header).size = size as u64 }; + let desc_head = unsafe { (header).add(1) } as *mut MemoryDescriptor; + for (i, desc) in memory_map.enumerate() { + unsafe { *desc_head.add(i) = *desc }; + } + } - let kernel_main_arg = KernelMainArg { graphics_info }; + let kernel_main_arg = KernelMainArg { + graphics_info, + memory_map_entry: mem_map_buf.as_ptr() as *const _, + }; let kernel_main: KernelMain = unsafe { core::mem::transmute(entry_point as usize) }; diff --git a/common/Cargo.lock b/common/Cargo.lock index db83ec7..752298f 100644 --- a/common/Cargo.lock +++ b/common/Cargo.lock @@ -2,6 +2,87 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "common" version = "0.1.0" +dependencies = [ + "uefi-raw", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "uefi-raw" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7" +dependencies = [ + "bitflags", + "ptr_meta", + "uguid", +] + +[[package]] +name = "uguid" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/common/Cargo.toml b/common/Cargo.toml index b7723d9..9b906de 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +uefi-raw = "0.5.0" diff --git a/common/src/types.rs b/common/src/types.rs index a522a46..bc03ccf 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -1,7 +1,75 @@ +pub use uefi_raw::table::boot::MemoryDescriptor; +pub use uefi_raw::table::boot::MemoryType; + #[repr(C)] #[derive(Debug, Clone)] pub struct KernelMainArg { pub graphics_info: GraphicsInfo, + pub memory_map_entry: *const MemMapEntry, +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct MemMapEntry { + pub size: u64, +} + +#[derive(Debug, Clone)] +pub struct MemMapIter<'a> { + index: usize, + size: usize, + current: *const MemoryDescriptor, + _lifetime: core::marker::PhantomData<&'a MemoryDescriptor>, +} + +impl MemMapEntry { + /// # Safety + /// The caller must ensure that entry has enough size to store the given iterator. + /// And header(=MemMapEntry) can be placed at the beginning of the entry. + pub unsafe fn new_inplace<'a, 'b>( + entry: &'a mut [u8], + size: u64, + iter: impl ExactSizeIterator + Clone, + ) { + let header = entry.as_mut_ptr() as *mut MemMapEntry; + (*header).size = size; + let desc_head = unsafe { (header).add(1) } as *mut MemoryDescriptor; + for (i, desc) in iter.enumerate() { + unsafe { *desc_head.add(i) = *desc }; + } + } + + /// # Safety + /// The caller must ensure that an array(len = self.size) of MemoryDescriptor are + /// placed after this struct. + pub unsafe fn into_iter(&self) -> MemMapIter<'_> { + let current = unsafe { (self as *const MemMapEntry).add(1) } as *const MemoryDescriptor; + MemMapIter { + index: 0, + current, + size: self.size as usize, + _lifetime: core::marker::PhantomData, + } + } +} + +impl<'a> Iterator for MemMapIter<'a> { + type Item = MemoryDescriptor; + + fn next(&mut self) -> Option { + if self.index >= self.size { + return None; + } + let current = unsafe { self.current.add(self.index) }; + self.index += 1; + Some(unsafe { *current }) + } +} + +impl<'a> ExactSizeIterator for MemMapIter<'a> { + fn len(&self) -> usize { + self.size + } } pub type KernelMain = extern "C" fn(arg: *const KernelMainArg) -> !; @@ -24,6 +92,16 @@ pub struct GraphicsInfo { } impl GraphicsInfo { + pub const fn uninitialized() -> Self { + Self { + horizontal_resolution: 0, + vertical_resolution: 0, + pixels_per_scan_line: 0, + frame_buffer_base: core::ptr::null_mut(), + pixcel_format: PixcelFormat::Rgb, + } + } + pub fn new( horizontal_resolution: usize, vertical_resolution: usize, diff --git a/kernel-lib/Cargo.lock b/kernel-lib/Cargo.lock index 8ab7f8a..7b5b276 100644 --- a/kernel-lib/Cargo.lock +++ b/kernel-lib/Cargo.lock @@ -14,6 +14,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "cfg-if" version = "1.0.0" @@ -23,6 +29,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "common" version = "0.1.0" +dependencies = [ + "uefi-raw", +] [[package]] name = "dummy-waker" @@ -37,7 +46,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn", + "syn 2.0.15", ] [[package]] @@ -108,6 +117,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.27" @@ -162,6 +191,17 @@ dependencies = [ "lock_api", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.15" @@ -173,6 +213,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "uefi-raw" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7" +dependencies = [ + "bitflags", + "ptr_meta", + "uguid", +] + +[[package]] +name = "uguid" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5" + [[package]] name = "unicode-ident" version = "1.0.8" diff --git a/kernel-lib/src/alloc.rs b/kernel-lib/src/alloc.rs deleted file mode 100644 index edd484e..0000000 --- a/kernel-lib/src/alloc.rs +++ /dev/null @@ -1,312 +0,0 @@ -use core::{ - alloc::{Allocator, GlobalAlloc, Layout, LayoutError}, - mem::MaybeUninit, -}; - -extern crate alloc; -use crate::mutex::Mutex; -use alloc::boxed::Box; - -struct FixedLengthAllocatorInner { - heap: [u8; SIZE], - next: usize, -} -pub struct FixedLengthAllocator(Mutex>); - -unsafe impl<'a, const SIZE: usize> Allocator for &'a FixedLengthAllocator { - fn allocate( - &self, - layout: Layout, - ) -> Result, core::alloc::AllocError> { - let ptr = unsafe { GlobalAlloc::alloc(*self, layout) }; - if ptr.is_null() { - Err(core::alloc::AllocError) - } else { - Ok(unsafe { - core::ptr::NonNull::new_unchecked(core::slice::from_raw_parts_mut( - ptr, - layout.size(), - )) - }) - } - } - - unsafe fn deallocate(&self, ptr: core::ptr::NonNull, layout: Layout) { - unsafe { GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) }; - } -} - -impl FixedLengthAllocator { - pub const fn new() -> Self { - Self(Mutex::new(FixedLengthAllocatorInner::new())) - } -} - -impl FixedLengthAllocatorInner { - pub const fn new() -> Self { - Self { - heap: [0; SIZE], - next: 0, - } - } -} - -fn ceil(value: usize, alignment: usize) -> usize { - (value + alignment - 1) & !(alignment - 1) -} - -unsafe impl BoundaryAlloc for FixedLengthAllocator { - unsafe fn alloc(&self, layout: Layout, boundary: usize) -> *mut u8 { - let mut allocator = crate::lock!(self.0); - let start = allocator.next; - let current_ptr = allocator.heap.as_mut_ptr().add(start); - let mut alloc_ptr = ceil(current_ptr as usize, layout.align()); - if boundary > 0 { - let next_boundary = ceil(alloc_ptr, boundary); - // if allocated area steps over boundary - if next_boundary < alloc_ptr + layout.size() { - alloc_ptr = next_boundary; - } - } - let end = alloc_ptr + layout.size() - allocator.heap.as_ptr() as usize; - if end > SIZE { - panic!("[ALLOCATOR] Out of memory"); - #[allow(unreachable_code)] - core::ptr::null_mut() - } else { - allocator.next = end; - alloc_ptr as *mut u8 - } - } - - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { - // Do nothing - } -} - -/// # Safety -/// Type impls this trait must properly allocate or deallocate memory -pub unsafe trait BoundaryAlloc { - /// This Safety clause is brought from GlobalAlloc - /// # Safety - /// This function is unsafe because undefined behavior can result if the caller does not ensure that layout has non-zero size. - unsafe fn alloc(&self, layout: Layout, boundary: usize) -> *mut u8; - - /// This Safety clause is brought from GlobalAlloc - /// # Safety - /// This function is unsafe because undefined behavior can result if the caller does not ensure all of the following: - /// - ptr must denote a block of memory currently allocated via this allocator, - /// - layout must be the same layout that was used to allocate that block of memory. - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); -} - -unsafe impl GlobalAlloc for FixedLengthAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - BoundaryAlloc::alloc(self, layout, 0) - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - BoundaryAlloc::dealloc(self, ptr, layout); - } -} - -pub fn alloc_with_boundary_raw( - allocator: &impl BoundaryAlloc, - layout: Layout, - boundary: usize, -) -> *mut u8 { - unsafe { BoundaryAlloc::alloc(allocator, layout, boundary) } -} - -pub fn alloc_with_boundary( - allocator: &FixedLengthAllocator, - alignment: usize, - boundary: usize, -) -> Result, &'_ FixedLengthAllocator>, LayoutError> { - let layout = Layout::from_size_align(core::mem::size_of::(), alignment)?; - let ptr = alloc_with_boundary_raw(allocator, layout, boundary) as *mut MaybeUninit; - log::debug!("allocating {:x}", ptr as usize); - let (until, heap_start, heap_end) = { - let allocator = crate::lock!(allocator.0); - ( - allocator.next, - allocator.heap.as_ptr() as usize, - allocator.heap.as_ptr() as usize + SIZE, - ) - }; - log::debug!( - "[{:x}..{:x}] in [{:x}...{:x}]", - ptr as usize, - until, - heap_start, - heap_end - ); - debug_assert!(!ptr.is_null()); - Ok(unsafe { Box::from_raw_in(ptr, allocator) }) -} - -pub fn alloc_with_boundary_with_default_else( - allocator: &FixedLengthAllocator, - alignment: usize, - boundary: usize, - default: impl FnOnce() -> T, -) -> Result>, LayoutError> { - let mut allocated = alloc_with_boundary::(allocator, alignment, boundary)?; - let ptr = allocated.as_mut_ptr(); - unsafe { ptr.write(default()) }; - Ok(unsafe { allocated.assume_init() }) -} - -pub fn alloc_array_with_boundary( - allocator: &FixedLengthAllocator, - len: usize, - alignment: usize, - boundary: usize, -) -> Result], &'_ FixedLengthAllocator>, LayoutError> { - let size = len * core::mem::size_of::(); - let layout = Layout::from_size_align(size, alignment)?; - let array_pointer = alloc_with_boundary_raw(allocator, layout, boundary) as *mut MaybeUninit; - debug_assert!(!array_pointer.is_null()); - let slice = unsafe { core::slice::from_raw_parts_mut(array_pointer, len) }; - Ok(unsafe { Box::from_raw_in(slice, allocator) }) -} - -pub fn alloc_array_with_boundary_with_default_else( - allocator: &FixedLengthAllocator, - len: usize, - alignment: usize, - boundary: usize, - default: impl Fn() -> T, -) -> Result>, LayoutError> { - let mut uninit_array = - alloc_array_with_boundary::(allocator, len, alignment, boundary)?; - for val in uninit_array.iter_mut() { - unsafe { val.as_mut_ptr().write(default()) }; - } - // Safety: array is initialized - Ok(unsafe { uninit_array.assume_init() }) -} - -#[cfg(test)] -mod tests { - - use super::*; - #[test] - fn alignment_test() { - let allocator = FixedLengthAllocator::<2048>::new(); - unsafe { - let align1 = 4; - let size1 = 3; - let ptr1 = - GlobalAlloc::alloc(&allocator, Layout::from_size_align(size1, align1).unwrap()); - assert!(ptr1 as usize % align1 == 0); - - let align2 = 64; - let size2 = 1024; - let ptr2 = - GlobalAlloc::alloc(&allocator, Layout::from_size_align(size2, align2).unwrap()); - assert!(ptr2 as usize > ptr1 as usize + size1 - 1); - assert!(ptr2 as usize % 64 == 0); - - let align3 = 512; - let size3 = 64; - let ptr3 = - GlobalAlloc::alloc(&allocator, Layout::from_size_align(size3, align3).unwrap()); - assert!(ptr3 as usize > ptr2 as usize + size2 - 1); - assert!(ptr3 as usize % align3 == 0); - } - } - - #[test] - fn boundary_test() { - let allocator = FixedLengthAllocator::<2048>::new(); - let boundary = 4; - let alignment = 4; - let size = 3; - let ptr1 = alloc_with_boundary_raw( - &allocator, - Layout::from_size_align(size, alignment).unwrap(), - boundary, - ) as usize; - assert!(ptr1 % alignment == 0); - let prev_boundary = ptr1 - (ptr1 % boundary); - assert!(prev_boundary <= ptr1 && ptr1 + size - 1 < prev_boundary + boundary); - let boundary = 2048; - let alignment = 64; - let size = 1024; - let ptr2 = alloc_with_boundary_raw( - &allocator, - Layout::from_size_align(size, alignment).unwrap(), - boundary, - ) as usize; - assert!(ptr2 % alignment == 0); - let prev_boundary = ptr2 - (ptr2 % boundary); - assert!(prev_boundary <= ptr2 && ptr2 + size - 1 < prev_boundary + boundary); - let boundary = 512; - let alignment = 512; - let size = 64; - let ptr3 = alloc_with_boundary_raw( - &allocator, - Layout::from_size_align(size, alignment).unwrap(), - boundary, - ) as usize; - assert!(ptr3 % alignment == 0); - let prev_boundary = ptr3 - (ptr3 % boundary); - assert!(prev_boundary <= ptr3 && ptr3 + size - 1 < prev_boundary + boundary); - } - - #[test] - fn alloc_array_test() { - let allocator = FixedLengthAllocator::<4096>::new(); - let alignment = 64; - let len = 100; - let boundary = 1024; - let array = - alloc_array_with_boundary::<_, u64>(&allocator, len, alignment, boundary).unwrap(); - let start_ptr = array.as_ptr() as usize; - let end_ptr = start_ptr + array.len() * core::mem::size_of::(); - // check boundary - let prev_boundary = start_ptr - (start_ptr % boundary); - assert!(prev_boundary <= start_ptr && end_ptr - 1 < (prev_boundary + boundary)); - // check alignment - assert!(start_ptr % alignment == 0); - // check length - assert_eq!(array.len(), len); - - let alignment2 = 4; - let len2 = 100; - let boundary2 = 1024; - let array2 = - alloc_array_with_boundary::<_, u64>(&allocator, len2, alignment2, boundary2).unwrap(); - let start_ptr2 = array2.as_ptr() as usize; - let end_ptr2 = start_ptr2 + array2.len() * core::mem::size_of::(); - // check boundary - let prev_boundary2 = start_ptr2 - (start_ptr2 % boundary2); - assert!(prev_boundary2 <= start_ptr2 && end_ptr2 - 1 < (prev_boundary2 + boundary2)); - // check alignment - assert!(start_ptr % alignment2 == 0); - // check length - assert_eq!(array2.len(), len2); - - // check that the two arrays are not overlapping - assert!(end_ptr <= start_ptr2); - - let alignment3 = 1024; - let len3 = 1024; - let boundary3 = 1024; - let array3 = - alloc_array_with_boundary::<_, u8>(&allocator, len3, alignment3, boundary3).unwrap(); - let start_ptr3 = array3.as_ptr() as usize; - let end_ptr3 = start_ptr3 + array3.len() * core::mem::size_of::(); // this ptr is not included in the array - - // check boundary - let prev_boundary3 = start_ptr3 - (start_ptr3 % boundary3); - assert!(prev_boundary3 <= start_ptr3 && end_ptr3 - 1 < (prev_boundary3 + boundary3)); - // check alignment - assert!(start_ptr3 % alignment3 == 0); - // check length - assert_eq!(array3.len(), len3); - // check that the two arrays are not overlapping - assert!(end_ptr2 <= start_ptr3); - } -} diff --git a/kernel-lib/src/allocator.rs b/kernel-lib/src/allocator.rs new file mode 100644 index 0000000..509081e --- /dev/null +++ b/kernel-lib/src/allocator.rs @@ -0,0 +1,343 @@ +pub mod bump_allocator; +pub mod fixed_length_allocator; + +extern crate alloc; +use alloc::boxed::Box; +use core::{ + alloc::{Allocator, Layout}, + mem::MaybeUninit, + ops::Range, +}; +pub use fixed_length_allocator::FixedLengthAllocator; + +/// # Safety +/// Type impls this trait must properly allocate or deallocate memory +pub unsafe trait BoundaryAlloc { + /// This Safety clause is brought from GlobalAlloc + /// # Safety + /// This function is unsafe because undefined behavior can result if the caller does not ensure that layout has non-zero size. + unsafe fn alloc(&self, layout: Layout, boundary: usize) -> *mut u8; + + /// This Safety clause is brought from GlobalAlloc + /// # Safety + /// This function is unsafe because undefined behavior can result if the caller does not ensure all of the following: + /// - ptr must denote a block of memory currently allocated via this allocator, + /// - layout must be the same layout that was used to allocate that block of memory. + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AllocationError; + +fn ceil(value: usize, alignment: usize) -> usize { + (value + alignment - 1) & !(alignment - 1) +} +pub(crate) fn align_and_boundary_to( + from_ptr: usize, + layout: Layout, + boundary: usize, +) -> Result, ()> { + debug_assert!(boundary == 0 || boundary.is_power_of_two()); + debug_assert!(boundary == 0 || layout.size() <= boundary); + + let mut alloc_ptr = ceil(from_ptr, layout.align()); + if boundary > 0 { + let next_boundary = ceil(alloc_ptr, boundary); + // if allocated area steps over boundary + if next_boundary < alloc_ptr.checked_add(layout.size()).ok_or(())? { + alloc_ptr = next_boundary; + } + } + + let end_ptr = alloc_ptr.checked_add(layout.size()).ok_or(())?; + Ok(alloc_ptr..end_ptr) +} + +#[macro_export] +macro_rules! impl_global_alloc_for_boundary_alloc { + ($t:ty) => { + unsafe impl core::alloc::GlobalAlloc for $t { + unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { + $crate::allocator::BoundaryAlloc::alloc(self, layout, 0) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { + $crate::allocator::BoundaryAlloc::dealloc(self, ptr, layout) + } + } + }; +} + +#[macro_export] +macro_rules! impl_allocator_for_global_alloc { + ($t:ty) => { + unsafe impl<'a> core::alloc::Allocator for &'a $t { + fn allocate( + &self, + layout: core::alloc::Layout, + ) -> Result, core::alloc::AllocError> { + let ptr = unsafe { core::alloc::GlobalAlloc::alloc(*self, layout) }; + if ptr.is_null() { + Err(core::alloc::AllocError) + } else { + Ok(unsafe { + core::ptr::NonNull::new_unchecked(core::slice::from_raw_parts_mut( + ptr, + layout.size(), + )) + }) + } + } + + unsafe fn deallocate(&self, ptr: core::ptr::NonNull, layout: core::alloc::Layout) { + unsafe { core::alloc::GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) }; + } + } + }; +} + +pub fn alloc_with_boundary_raw( + allocator: &impl BoundaryAlloc, + layout: Layout, + boundary: usize, +) -> *mut u8 { + unsafe { BoundaryAlloc::alloc(allocator, layout, boundary) } +} + +pub fn alloc_with_boundary<'a, T, A>( + allocator: &'a A, + alignment: usize, + boundary: usize, +) -> Result, &'a A>, AllocationError> +where + A: BoundaryAlloc, + &'a A: Allocator, +{ + let layout = Layout::from_size_align(core::mem::size_of::(), alignment) + .map_err(|_| AllocationError {})?; + let ptr = alloc_with_boundary_raw(allocator, layout, boundary) as *mut MaybeUninit; + if ptr.is_null() { + return Err(AllocationError {}); + } + Ok(unsafe { Box::from_raw_in(ptr, allocator) }) +} + +pub fn alloc_with_boundary_with_default_else<'a, T, A>( + allocator: &'a A, + alignment: usize, + boundary: usize, + default: impl FnOnce() -> T, +) -> Result, AllocationError> +where + A: BoundaryAlloc, + &'a A: Allocator, +{ + let mut allocated = alloc_with_boundary::(allocator, alignment, boundary)?; + let ptr = allocated.as_mut_ptr(); + if ptr.is_null() { + return Err(AllocationError {}); + } + unsafe { ptr.write(default()) }; + Ok(unsafe { allocated.assume_init() }) +} + +pub fn alloc_array_with_boundary<'a, T, A>( + allocator: &'a A, + len: usize, + alignment: usize, + boundary: usize, +) -> Result], &'a A>, AllocationError> +where + A: BoundaryAlloc, + &'a A: Allocator, +{ + let size = len * core::mem::size_of::(); + let layout = Layout::from_size_align(size, alignment).map_err(|_| AllocationError {})?; + let array_pointer = alloc_with_boundary_raw(allocator, layout, boundary) as *mut MaybeUninit; + if array_pointer.is_null() { + return Err(AllocationError {}); + } + let slice = unsafe { core::slice::from_raw_parts_mut(array_pointer, len) }; + Ok(unsafe { Box::from_raw_in(slice, allocator) }) +} + +pub fn alloc_array_with_boundary_with_default_else<'a, T, A>( + allocator: &'a A, + len: usize, + alignment: usize, + boundary: usize, + default: impl Fn() -> T, +) -> Result, AllocationError> +where + A: BoundaryAlloc, + &'a A: Allocator, +{ + let mut uninit_array = alloc_array_with_boundary::(allocator, len, alignment, boundary)?; + for val in uninit_array.iter_mut() { + unsafe { val.as_mut_ptr().write(default()) }; + } + // Safety: array is initialized + Ok(unsafe { uninit_array.assume_init() }) +} + +#[cfg(test)] +mod tests { + use super::*; + + pub fn alloc_huge_times_template( + allocator: &impl BoundaryAlloc, + n_times: usize, + upper_bound: usize, + ) { + use rand::Rng; + let mut rng = rand::thread_rng(); + for _ in 0..n_times { + let alignment: usize = rng.gen_range(1..upper_bound); + // alignment must be power of 2 + let alignment = 2i32.pow(alignment.ilog2()) as usize; + let size = rng.gen_range(0..upper_bound); + let mut boundary: usize; + if rng.gen_bool(0.99) { + boundary = rng.gen_range(size..upper_bound); + // boundary must be power of 2 + boundary = 2i32.pow(boundary.ilog2()) as usize; + if boundary < size { + boundary *= 2; + } + } else { + boundary = 0; + } + let ptr = unsafe { + BoundaryAlloc::alloc( + allocator, + Layout::from_size_align(size, alignment).unwrap(), + boundary, + ) + }; + assert!(ptr as usize % alignment == 0); + if boundary != 0 { + // boundary check + let prev_boundary = ptr as usize - (ptr as usize % boundary); + assert!( + prev_boundary <= ptr as usize && ptr as usize + size - 1 < prev_boundary + boundary, + "alignment: {:x}, boundary: {:x}, size: {:x}\nallocated area: {:p} - {:p}, boundary: {:p} - {:p}", + alignment, + boundary, + size, + ptr, + (ptr as usize + size - 1) as *mut u8, + prev_boundary as *mut u8, + (prev_boundary + boundary) as *mut u8 + ); + } + unsafe { + BoundaryAlloc::dealloc( + allocator, + ptr, + Layout::from_size_align(size, alignment).unwrap(), + ); + } + } + } + + pub fn alloc_huge_times_with_value_template<'a, A>(allocator: &'a A, n_times: usize) + where + A: BoundaryAlloc, + &'a A: Allocator, + { + for i in 0..n_times { + let mut vec = Vec::::with_capacity_in(i, allocator); + let mut vec2 = Vec::::with_capacity_in(i, allocator); + let mut one = Box::::try_new_uninit_in(allocator).unwrap(); + unsafe { + one.as_mut_ptr().write_volatile(1); + } + for j in 0..i { + vec.push(core::hint::black_box(j)); + } + for j in 0..i { + vec2.push(core::hint::black_box(j)); + } + + assert_eq!(vec.len(), i); + for (j, val) in vec.into_iter().enumerate() { + assert_eq!(val, j); + assert_eq!(vec2[j], j); + } + assert_eq!(*unsafe { one.assume_init() }, 1); + } + } + + #[test] + fn ceil_test() { + assert_eq!(ceil(100, 4), 100); + assert_eq!(ceil(101, 4), 104); + } + + #[test] + fn align_and_boundary_to_test() { + assert_eq!( + align_and_boundary_to( + 0x1111, + Layout::from_size_align(0x100, 0x2000).unwrap(), + 0x400 + ), + Ok(0x2000..0x2100), + ); + } + + #[test] + fn alloc_array_test() { + let allocator = FixedLengthAllocator::<4096>::new(); + let alignment = 64; + let len = 100; + let boundary = 1024; + let array = + alloc_array_with_boundary::(&allocator, len, alignment, boundary).unwrap(); + let start_ptr = array.as_ptr() as usize; + let end_ptr = start_ptr + array.len() * core::mem::size_of::(); + // check boundary + let prev_boundary = start_ptr - (start_ptr % boundary); + assert!(prev_boundary <= start_ptr && end_ptr - 1 < (prev_boundary + boundary)); + // check alignment + assert!(start_ptr % alignment == 0); + // check length + assert_eq!(array.len(), len); + + let alignment2 = 4; + let len2 = 100; + let boundary2 = 1024; + let array2 = + alloc_array_with_boundary::(&allocator, len2, alignment2, boundary2).unwrap(); + let start_ptr2 = array2.as_ptr() as usize; + let end_ptr2 = start_ptr2 + array2.len() * core::mem::size_of::(); + // check boundary + let prev_boundary2 = start_ptr2 - (start_ptr2 % boundary2); + assert!(prev_boundary2 <= start_ptr2 && end_ptr2 - 1 < (prev_boundary2 + boundary2)); + // check alignment + assert!(start_ptr % alignment2 == 0); + // check length + assert_eq!(array2.len(), len2); + + // check that the two arrays are not overlapping + assert!(end_ptr <= start_ptr2); + + let alignment3 = 1024; + let len3 = 1024; + let boundary3 = 1024; + let array3 = + alloc_array_with_boundary::(&allocator, len3, alignment3, boundary3).unwrap(); + let start_ptr3 = array3.as_ptr() as usize; + let end_ptr3 = start_ptr3 + array3.len() * core::mem::size_of::(); // this ptr is not included in the array + + // check boundary + let prev_boundary3 = start_ptr3 - (start_ptr3 % boundary3); + assert!(prev_boundary3 <= start_ptr3 && end_ptr3 - 1 < (prev_boundary3 + boundary3)); + // check alignment + assert!(start_ptr3 % alignment3 == 0); + // check length + assert_eq!(array3.len(), len3); + // check that the two arrays are not overlapping + assert!(end_ptr2 <= start_ptr3); + } +} diff --git a/kernel-lib/src/allocator/bump_allocator.rs b/kernel-lib/src/allocator/bump_allocator.rs new file mode 100644 index 0000000..b03c296 --- /dev/null +++ b/kernel-lib/src/allocator/bump_allocator.rs @@ -0,0 +1,90 @@ +use crate::{impl_allocator_for_global_alloc, impl_global_alloc_for_boundary_alloc}; + +use super::{align_and_boundary_to, BoundaryAlloc}; + +pub struct BumpAllocator { + heap_start: usize, + heap_end: usize, + next: usize, + n_allocations: usize, +} + +impl BumpAllocator { + pub const fn new() -> Self { + Self { + heap_start: 0, + heap_end: 0, + next: 0, + n_allocations: 0, + } + } + + /// Initialize the allocator with the given heap range + /// # Safety + /// The caller must ensure that the given heap range is unused permanently. + /// Also, this method must be called only once. + pub unsafe fn init(&mut self, heap_start: usize, heap_end: usize) { + self.heap_start = heap_start; + self.heap_end = heap_end; + self.next = heap_start; + } +} + +unsafe impl BoundaryAlloc for crate::mutex::Mutex { + unsafe fn alloc(&self, layout: core::alloc::Layout, boundary: usize) -> *mut u8 { + let mut allocator = crate::lock!(self); + let Ok(alloc_start) = align_and_boundary_to(allocator.next, layout, boundary) else { + return core::ptr::null_mut(); + }; + + if alloc_start.end >= allocator.heap_end { + return core::ptr::null_mut(); + } + + allocator.next = alloc_start.end; + allocator.n_allocations += 1; + + alloc_start.start as *mut u8 + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: core::alloc::Layout) { + let mut allocator = crate::lock!(self); + allocator.n_allocations -= 1; + if allocator.n_allocations == 0 { + log::debug!("dealloc: Resetting allocator"); + allocator.next = allocator.heap_start; + } + } +} + +impl_global_alloc_for_boundary_alloc!(crate::mutex::Mutex); +impl_allocator_for_global_alloc!(crate::mutex::Mutex); + +#[cfg(test)] +mod tests { + use super::*; + use crate::allocator::tests::{ + alloc_huge_times_template, alloc_huge_times_with_value_template, + }; + #[test] + fn alloc_huge_times() { + const SIZE: usize = 100 * 1024; + static HEAP: &[u8] = &[0u8; SIZE]; + let allocator = crate::mutex::Mutex::new(BumpAllocator::new()); + unsafe { + crate::lock!(allocator).init(HEAP.as_ptr() as usize, HEAP.as_ptr() as usize + SIZE) + }; + alloc_huge_times_template(&allocator, SIZE / 1024, 1000); + } + + #[test] + fn alloc_huge_times_with_value() { + const SIZE: usize = 100 * 1024; + static mut HEAP: [u8; SIZE] = [0u8; SIZE]; + let allocator = crate::mutex::Mutex::new(BumpAllocator::new()); + unsafe { + crate::lock!(allocator).init(HEAP.as_ptr() as usize, HEAP.as_ptr() as usize + SIZE) + }; + alloc_huge_times_with_value_template(&allocator, SIZE / 1024); + } +} diff --git a/kernel-lib/src/allocator/fixed_length_allocator.rs b/kernel-lib/src/allocator/fixed_length_allocator.rs new file mode 100644 index 0000000..25e2a78 --- /dev/null +++ b/kernel-lib/src/allocator/fixed_length_allocator.rs @@ -0,0 +1,194 @@ +use crate::allocator::BoundaryAlloc; +use core::alloc::{Allocator, GlobalAlloc, Layout}; + +extern crate alloc; +use crate::mutex::Mutex; + +struct FixedLengthAllocatorInner { + heap: [u8; SIZE], + /// next in 0..SIZE, which is the index of the next available byte + next: usize, +} +pub struct FixedLengthAllocator(Mutex>); + +unsafe impl<'a, const SIZE: usize> Allocator for &'a FixedLengthAllocator { + fn allocate( + &self, + layout: Layout, + ) -> Result, core::alloc::AllocError> { + let ptr = unsafe { GlobalAlloc::alloc(*self, layout) }; + if ptr.is_null() { + Err(core::alloc::AllocError) + } else { + Ok(unsafe { + core::ptr::NonNull::new_unchecked(core::slice::from_raw_parts_mut( + ptr, + layout.size(), + )) + }) + } + } + + unsafe fn deallocate(&self, ptr: core::ptr::NonNull, layout: Layout) { + unsafe { GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) }; + } +} + +impl FixedLengthAllocator { + pub const fn new() -> Self { + Self(Mutex::new(FixedLengthAllocatorInner::new())) + } +} + +impl FixedLengthAllocatorInner { + pub const fn new() -> Self { + Self { + heap: [0; SIZE], + next: 0, + } + } + + pub fn heap_range(&self) -> core::ops::Range { + self.heap.as_ptr() as usize..self.heap_end() + } + + /// Return the end of heap (which is not included in heap) + pub fn heap_end(&self) -> usize { + self.heap.as_ptr() as usize + SIZE + } +} + +unsafe impl BoundaryAlloc for FixedLengthAllocator { + unsafe fn alloc(&self, layout: Layout, boundary: usize) -> *mut u8 { + debug_assert!(boundary == 0 || boundary.is_power_of_two()); + let mut allocator = crate::lock!(self.0); + let start = allocator.next; + let current_ptr = allocator.heap.as_mut_ptr().add(start); + let Ok(alloc_range) = + crate::allocator::align_and_boundary_to(current_ptr as usize, layout, boundary) + else { + panic!("[ALLOCATOR] Failed to allocate"); + }; + if alloc_range.end >= allocator.heap_end() { + #[cfg(test)] + std::eprintln!( + "layout: {:x?}, boundary: 0x{:x}, heap: {:x?}, alloc_range: {:x?}, next: {:x}", + layout, + boundary, + allocator.heap_range(), + alloc_range, + allocator.next + ); + panic!("[ALLOCATOR] Out of memory"); + #[allow(unreachable_code)] + core::ptr::null_mut() + } else { + allocator.next = alloc_range.end - allocator.heap_range().start; + alloc_range.start as *mut u8 + } + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + // Do nothing + } +} + +unsafe impl GlobalAlloc for FixedLengthAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + BoundaryAlloc::alloc(self, layout, 0) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + BoundaryAlloc::dealloc(self, ptr, layout); + } +} + +#[cfg(test)] +mod tests { + use crate::allocator; + + use super::*; + #[test] + fn alignment_test() { + let allocator = FixedLengthAllocator::<2048>::new(); + unsafe { + let align1 = 4; + let size1 = 3; + let ptr1 = + GlobalAlloc::alloc(&allocator, Layout::from_size_align(size1, align1).unwrap()); + assert!(ptr1 as usize % align1 == 0); + + let align2 = 64; + let size2 = 1024; + let ptr2 = + GlobalAlloc::alloc(&allocator, Layout::from_size_align(size2, align2).unwrap()); + assert!(ptr2 as usize > ptr1 as usize + size1 - 1); + assert!(ptr2 as usize % 64 == 0); + + let align3 = 512; + let size3 = 64; + let ptr3 = + GlobalAlloc::alloc(&allocator, Layout::from_size_align(size3, align3).unwrap()); + assert!(ptr3 as usize > ptr2 as usize + size2 - 1); + assert!(ptr3 as usize % align3 == 0); + } + } + + #[test] + fn boundary_test() { + let allocator = FixedLengthAllocator::<2048>::new(); + let boundary = 4; + let alignment = 4; + let size = 3; + let ptr1 = unsafe { + BoundaryAlloc::alloc( + &allocator, + Layout::from_size_align(size, alignment).unwrap(), + boundary, + ) as usize + }; + assert!(ptr1 % alignment == 0); + let prev_boundary = ptr1 - (ptr1 % boundary); + assert!(prev_boundary <= ptr1 && ptr1 + size - 1 < prev_boundary + boundary); + let boundary = 2048; + let alignment = 64; + let size = 1024; + let ptr2 = unsafe { + BoundaryAlloc::alloc( + &allocator, + Layout::from_size_align(size, alignment).unwrap(), + boundary, + ) as usize + }; + assert!(ptr2 % alignment == 0); + let prev_boundary = ptr2 - (ptr2 % boundary); + assert!(prev_boundary <= ptr2 && ptr2 + size - 1 < prev_boundary + boundary); + let boundary = 512; + let alignment = 512; + let size = 64; + let ptr3 = unsafe { + BoundaryAlloc::alloc( + &allocator, + Layout::from_size_align(size, alignment).unwrap(), + boundary, + ) as usize + }; + assert!(ptr3 % alignment == 0); + let prev_boundary = ptr3 - (ptr3 % boundary); + assert!(prev_boundary <= ptr3 && ptr3 + size - 1 < prev_boundary + boundary); + } + + #[test] + fn alloc_huge_times() { + const SIZE: usize = 100 * 1024; + let allocator = FixedLengthAllocator::::new(); + allocator::tests::alloc_huge_times_template(&allocator, SIZE / 1024, 1000); + } + + #[test] + fn alloc_huge_times_with_value() { + const SIZE: usize = 100 * 1024; + let allocator = FixedLengthAllocator::::new(); + allocator::tests::alloc_huge_times_with_value_template(&allocator, SIZE / 1024); + } +} diff --git a/kernel-lib/src/layer.rs b/kernel-lib/src/layer.rs new file mode 100644 index 0000000..b981ad8 --- /dev/null +++ b/kernel-lib/src/layer.rs @@ -0,0 +1,272 @@ +extern crate alloc; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +use alloc::boxed::Box; +use alloc::collections::VecDeque; +use alloc::vec::Vec; +use alloc::{collections::BTreeMap, vec}; + +use crate::pixel::RenderedPixel; +use crate::{AsciiWriter, Color, PixcelWritableMut}; + +#[derive(Debug, Clone, Copy)] +pub struct Position { + pub x: usize, + pub y: usize, +} + +impl Position { + pub const fn new(x: usize, y: usize) -> Self { + Self { x, y } + } +} + +pub struct Window { + transparent_color: Option, + rendering_handler: Box, + buffer: Vec, + pixels: Vec>, + position: Position, +} + +impl Window { + pub fn new( + width: usize, + height: usize, + rendering_handler: Box, + transparent_color: Option, + position: Position, + ) -> Self { + let mut pixels = Vec::with_capacity(width); + for _ in 0..width { + pixels.push(vec![transparent_color.unwrap_or(Color::black()); height]); + } + let buffer = vec![0; width * height * 4]; + Self { + rendering_handler, + buffer, + transparent_color, + pixels, + position, + } + } + + pub fn move_to(&mut self, new_position: Position) { + self.position = new_position; + } + + pub fn move_relative(&mut self, x_diff: isize, y_diff: isize) { + let x = self.position.x as isize + x_diff; + let y = self.position.y as isize + y_diff; + self.position.x = x.try_into().unwrap_or(0); + self.position.y = y.try_into().unwrap_or(0); + } + + pub fn width(&self) -> usize { + self.pixels.len() + } + + pub fn height(&self) -> usize { + self.pixels[0].len() + } + + pub fn position(&self) -> Position { + self.position + } + + pub fn flush(&self, writer: &(dyn AsciiWriter + Send + Sync)) { + if let Some(transparent_color) = self.transparent_color { + for y in self.position.y + ..core::cmp::min( + self.position.y + self.height(), + writer.horizontal_resolution(), + ) + { + for x in self.position.x + ..core::cmp::min( + self.position.x + self.width(), + writer.pixcels_per_scan_line(), + ) + { + let color = self.pixels[x - self.position.x][y - self.position.y]; + if color == transparent_color { + continue; + } + writer.write(x, y, color); + } + } + } else { + // let frame_buffer_base = writer.frame_buffer_base(); + // let height = core::cmp::min( + // self.height(), + // writer.horizontal_resolution() - self.position.y, + // ); + // for y in 0..height { + // let offset = + // (self.position.y + y) * writer.pixcels_per_scan_line() + self.position.x * 4; + // let frame_buffer_row_base = unsafe { frame_buffer_base.add(offset) }; + // let width = core::cmp::min( + // self.width(), + // writer.pixcels_per_scan_line() - self.position.x, + // ); + // let frame_buffer_row_slice = + // unsafe { core::slice::from_raw_parts_mut(frame_buffer_row_base, width) }; + + // let buffer_row_slice = &self.buffer[(y * self.width())..(y * self.width() + width)]; + // log::debug!("buffer_row_slice: {:?}", buffer_row_slice.as_ptr_range()); + // log::debug!( + // "frame_buffer_row_slice: {:?}", + // frame_buffer_row_slice.as_ptr_range() + // ); + // frame_buffer_row_slice.copy_from_slice(buffer_row_slice); + // } + let y_range = self.position.y + ..core::cmp::min( + self.position.y + self.height(), + writer.horizontal_resolution(), + ); + let x_range = self.position.x + ..core::cmp::min( + self.position.x + self.width(), + writer.pixcels_per_scan_line(), + ); + let get_frame_buffer_index = + |x: usize, y: usize| (x + y * writer.pixcels_per_scan_line()) * 4; + let get_buffer_index = |x: usize, y: usize| (x + y * self.width()) * 4; + let frame_buffer_base = writer.frame_buffer_base(); + for y in y_range { + let offset = get_frame_buffer_index(x_range.start, y); + let frame_buffer_row_base = unsafe { frame_buffer_base.add(offset) }; + let width = (x_range.end - x_range.start) * 4; + let frame_buffer_row_slice = + unsafe { core::slice::from_raw_parts_mut(frame_buffer_row_base, width) }; + + let buffer_row_slice = &self.buffer[get_buffer_index( + x_range.start - self.position.x, + y - self.position.y, + ) + ..get_buffer_index(x_range.end - self.position.x, y - self.position.y)]; + + frame_buffer_row_slice.copy_from_slice(buffer_row_slice); + } + } + } + + pub fn write(&mut self, x: usize, y: usize, c: Color) { + self.pixels[x][y] = c; + let index = (x + y * self.width()) * 4; + self.buffer[index..index + 4].copy_from_slice(&self.rendering_handler.pixel(c)); + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct LayerId(usize); + +impl LayerId { + pub const fn uninitialized() -> Self { + Self(usize::MAX) + } +} + +pub struct Layer { + id: LayerId, + window: Window, +} + +impl Layer { + pub fn new(window: Window) -> Self { + static LATEST_UNUSED_ID: AtomicUsize = AtomicUsize::new(0); + let id = LayerId(LATEST_UNUSED_ID.fetch_add(1, Ordering::Relaxed)); + assert!(id < LayerId::uninitialized()); + Self { id, window } + } + + pub fn window(&self) -> &Window { + &self.window + } + + pub fn id(&self) -> LayerId { + self.id + } +} + +impl PixcelWritableMut for Layer { + fn write(&mut self, x: usize, y: usize, color: Color) { + self.window.write(x, y, color); + } +} + +pub struct LayerManager<'a> { + writer: &'a (dyn AsciiWriter + Send + Sync), + layer_stack: VecDeque, + layers: BTreeMap, +} + +impl<'a> LayerManager<'a> { + pub fn new(writer: &'a (dyn AsciiWriter + Send + Sync)) -> Self { + let layers = BTreeMap::new(); + Self { + writer, + layer_stack: VecDeque::new(), + layers, + } + } + pub fn new_layer(&mut self, window: Window) -> LayerId { + let layer = Layer::new(window); + let id = layer.id(); + + self.layer_stack.push_front(id); + self.layers.insert(id, layer); + + id + } + + pub fn move_layer(&mut self, id: LayerId, new_position: Position) { + let Some(layer) = self.layers.get_mut(&id) else { + return; + }; + + layer.window.move_to(new_position); + } + + pub fn move_relative(&mut self, id: LayerId, x_diff: isize, y_diff: isize) { + let Some(layer) = self.layers.get_mut(&id) else { + return; + }; + + layer.window.move_relative(x_diff, y_diff); + } + + pub fn flush(&self) { + // clear + // let base = self.writer.frame_buffer_base(); + // let len = self.writer.vertical_resolution() * self.writer.pixcels_per_scan_line() * 4; + // unsafe { core::ptr::write_bytes(base, 0, len) } + + for layer_id in self.layer_stack.iter() { + let layer = self.layers.get(layer_id).unwrap(); + layer.window.flush(self.writer); + } + } + + pub fn set_to_top(&mut self, id: LayerId) { + self.hide(id); + self.layer_stack.push_back(id); + } + + pub fn hide(&mut self, id: LayerId) { + let Some(index) = self.layer_stack.iter().position(|&x| x == id) else { + return; + }; + self.layer_stack.remove(index); + } + + pub fn layer(&self, id: LayerId) -> Option<&Layer> { + self.layers.get(&id) + } + + pub fn layer_mut(&mut self, id: LayerId) -> Option<&mut Layer> { + self.layers.get_mut(&id) + } +} diff --git a/kernel-lib/src/lib.rs b/kernel-lib/src/lib.rs index c9250d0..4f3011e 100644 --- a/kernel-lib/src/lib.rs +++ b/kernel-lib/src/lib.rs @@ -3,10 +3,12 @@ #![feature(allocator_api)] #![feature(generic_arg_infer)] -pub mod alloc; +pub mod allocator; pub mod futures; +pub mod layer; pub mod logger; pub mod mutex; +pub mod pixel; pub mod render; pub mod shapes; pub mod write_to; @@ -52,12 +54,22 @@ pub trait PixcelInfo { fn horizontal_resolution(&self) -> usize; fn vertical_resolution(&self) -> usize; fn pixcels_per_scan_line(&self) -> usize; + fn frame_buffer_base(&self) -> *mut u8; } pub trait PixcelWritable { fn write(&self, x: usize, y: usize, color: Color); } +pub trait PixcelWritableMut { + fn write(&mut self, x: usize, y: usize, color: Color); +} +impl PixcelWritableMut for T { + fn write(&mut self, x: usize, y: usize, color: Color) { + PixcelWritable::write(self, x, y, color) + } +} + pub trait AsciiWriter: PixcelWritable + PixcelInfo + Renderer { fn write_ascii(&self, x: usize, y: usize, c: char, bg_color: Color, fg_color: Color) { let Some(font) = FONT.get(c as usize) else { @@ -237,6 +249,10 @@ mod test { fn pixcels_per_scan_line(&self) -> usize { self.horizontal_resolution() / 4 } + + fn frame_buffer_base(&self) -> *mut u8 { + panic!("should not be called") + } } impl AsciiWriter for MockWriter { diff --git a/kernel-lib/src/pixel.rs b/kernel-lib/src/pixel.rs new file mode 100644 index 0000000..f64f871 --- /dev/null +++ b/kernel-lib/src/pixel.rs @@ -0,0 +1,44 @@ +extern crate alloc; +use alloc::boxed::Box; +use common::types::{GraphicsInfo, PixcelFormat}; + +use crate::Color; + +#[derive(Debug, Clone, Copy)] +pub struct Rgb; +#[derive(Debug, Clone, Copy)] +pub struct Bgr; + +pub trait MarkerColor: Copy { + fn pixcel_format() -> PixcelFormat; +} +impl MarkerColor for Rgb { + fn pixcel_format() -> PixcelFormat { + PixcelFormat::Rgb + } +} +impl MarkerColor for Bgr { + fn pixcel_format() -> PixcelFormat { + PixcelFormat::Bgr + } +} +pub trait RenderedPixel { + fn pixel(&self, c: Color) -> [u8; 4]; +} + +impl RenderedPixel for Rgb { + fn pixel(&self, c: Color) -> [u8; 4] { + [c.r, c.g, c.b, 0xff] + } +} +impl RenderedPixel for Bgr { + fn pixel(&self, c: Color) -> [u8; 4] { + [c.b, c.g, c.r, 0xff] + } +} +pub fn new_rendering_handler(graphics_info: GraphicsInfo) -> Box { + match graphics_info.pixcel_format() { + PixcelFormat::Rgb => Box::new(Rgb), + PixcelFormat::Bgr => Box::new(Bgr), + } +} diff --git a/kernel-lib/src/render.rs b/kernel-lib/src/render.rs index ff5d8ba..8a04f81 100644 --- a/kernel-lib/src/render.rs +++ b/kernel-lib/src/render.rs @@ -3,7 +3,7 @@ use core::ops::{Add, AddAssign}; use alloc::vec::Vec; -use crate::{shapes::Shape, Color, PixcelWritable}; +use crate::{shapes::Shape, Color, PixcelWritable, PixcelWritableMut}; #[derive(Debug)] pub struct AtomicVec2D { @@ -113,4 +113,58 @@ pub trait Renderer: PixcelWritable { } } +pub trait RendererMut: PixcelWritableMut { + fn fill_rect(&mut self, pos: Vector2D, size: Vector2D, color: Color) { + for y in pos.y..pos.y + size.y { + for x in pos.x..pos.x + size.x { + self.write(x, y, color); + } + } + } + + #[allow(clippy::needless_range_loop)] + fn render_board(&mut self, board: &Vec>, pos: Vector2D, size: usize, color: Color) { + let len = board.len(); + for y in 0..len { + for x in 0..len { + let block_pos = Vector2D::new(pos.x + x * size, pos.y + y * size); + if board[y][x] { + self.fill_rect( + Vector2D::new(block_pos.x + 1, block_pos.y + 1), + Vector2D::new(size - 1, size - 1), + color, + ); + } else { + self.fill_rect( + Vector2D::new(block_pos.x + 1, block_pos.y + 1), + Vector2D::new(size - 1, size - 1), + Color::black(), + ); + } + self.draw_rect_outline(block_pos, Vector2D::new(size, size), Color::white()); + } + } + } + + fn draw_rect_outline(&mut self, pos: Vector2D, size: Vector2D, color: Color) { + for x in pos.x..pos.x + size.x { + self.write(x, pos.y, color); + self.write(x, pos.y + size.y - 1, color); + } + for y in pos.y..pos.y + size.y { + self.write(pos.x, y, color); + self.write(pos.x + size.x - 1, y, color); + } + } + + fn fill_shape(&mut self, pos: Vector2D, shape: &dyn Shape) { + for y in 0..shape.get_height() { + for x in 0..shape.get_width() { + self.write(pos.x + x, pos.y + y, shape.get_pixel(x, y)); + } + } + } +} + impl Renderer for T where T: PixcelWritable {} +impl RendererMut for T where T: PixcelWritableMut {} diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 3a7c810..37c8e4d 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -43,6 +43,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bootkbd" version = "0.2.2" @@ -62,6 +68,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "common" version = "0.1.0" +dependencies = [ + "uefi-raw", +] [[package]] name = "crossbeam-queue" @@ -187,6 +196,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.29" @@ -245,6 +274,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "uefi-raw" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7" +dependencies = [ + "bitflags 2.4.1", + "ptr_meta", + "uguid", +] + +[[package]] +name = "uguid" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5" + [[package]] name = "unicode-ident" version = "1.0.10" @@ -270,7 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" dependencies = [ "bit_field", - "bitflags", + "bitflags 1.3.2", "rustversion", "volatile", ] diff --git a/kernel/src/alloc/alloc.rs b/kernel/src/alloc/alloc.rs index a441451..50804a8 100644 --- a/kernel/src/alloc/alloc.rs +++ b/kernel/src/alloc/alloc.rs @@ -1,28 +1,42 @@ extern crate alloc; use alloc::boxed::Box; -use core::{alloc::LayoutError, mem::MaybeUninit}; -use kernel_lib::alloc::FixedLengthAllocator; +use core::mem::MaybeUninit; +use kernel_lib::{ + allocator::{bump_allocator::BumpAllocator, AllocationError}, + mutex::Mutex, +}; -const HEAP_SIZE: usize = 1 << 21; - -pub type GlobalAllocator = FixedLengthAllocator; +pub type GlobalAllocator = Mutex; #[global_allocator] -static ALLOCATOR: GlobalAllocator = GlobalAllocator::new(); +static ALLOCATOR: GlobalAllocator = Mutex::new(BumpAllocator::new()); + +/// Initialize the global allocator. +/// # Safety +/// The caller must ensure that the given heap range is unused permanently. +/// Also, this method must be called only once. before any allocation. +pub unsafe fn init_allocator(heap_start: usize, heap_end: usize) { + log::debug!( + "Initializing allocator: {:#x} - {:#x}", + heap_start, + heap_end + ); + kernel_lib::lock!(ALLOCATOR).init(heap_start, heap_end); +} pub fn alloc_with_boundary( alignment: usize, boundary: usize, -) -> Result, &'static GlobalAllocator>, LayoutError> { - kernel_lib::alloc::alloc_with_boundary(&ALLOCATOR, alignment, boundary) +) -> Result, &'static GlobalAllocator>, AllocationError> { + kernel_lib::allocator::alloc_with_boundary(&ALLOCATOR, alignment, boundary) } pub fn alloc_with_boundary_with_default_else( alignment: usize, boundary: usize, default: impl FnOnce() -> T, -) -> Result, LayoutError> { - kernel_lib::alloc::alloc_with_boundary_with_default_else( +) -> Result, AllocationError> { + kernel_lib::allocator::alloc_with_boundary_with_default_else( &ALLOCATOR, alignment, boundary, default, ) } @@ -31,8 +45,8 @@ pub fn alloc_array_with_boundary( len: usize, alignment: usize, boundary: usize, -) -> Result], &'static GlobalAllocator>, LayoutError> { - kernel_lib::alloc::alloc_array_with_boundary(&ALLOCATOR, len, alignment, boundary) +) -> Result], &'static GlobalAllocator>, AllocationError> { + kernel_lib::allocator::alloc_array_with_boundary(&ALLOCATOR, len, alignment, boundary) } pub fn alloc_array_with_boundary_with_default_else( @@ -40,8 +54,8 @@ pub fn alloc_array_with_boundary_with_default_else( alignment: usize, boundary: usize, default: impl Fn() -> T, -) -> Result, LayoutError> { - kernel_lib::alloc::alloc_array_with_boundary_with_default_else( +) -> Result, AllocationError> { + kernel_lib::allocator::alloc_array_with_boundary_with_default_else( &ALLOCATOR, len, alignment, boundary, default, ) } diff --git a/kernel/src/graphics.rs b/kernel/src/graphics.rs index 0f31506..73f4a20 100644 --- a/kernel/src/graphics.rs +++ b/kernel/src/graphics.rs @@ -1,7 +1,10 @@ +extern crate alloc; use core::fmt::{self}; use common::types::{GraphicsInfo, PixcelFormat}; +use kernel_lib::layer::LayerManager; use kernel_lib::mutex::Mutex; +use kernel_lib::pixel::{Bgr, MarkerColor, Rgb}; use kernel_lib::{ logger::{CharWriter, DecoratedLog}, AsciiWriter, Color, PixcelInfo, PixcelWritable, Writer, @@ -10,25 +13,6 @@ use once_cell::unsync::OnceCell; use crate::serial_print; -#[derive(Debug, Clone, Copy)] -pub struct Rgb; -#[derive(Debug, Clone, Copy)] -pub struct Bgr; - -pub trait MarkerColor: Copy { - fn pixcel_format() -> PixcelFormat; -} -impl MarkerColor for Rgb { - fn pixcel_format() -> PixcelFormat { - PixcelFormat::Rgb - } -} -impl MarkerColor for Bgr { - fn pixcel_format() -> PixcelFormat { - PixcelFormat::Bgr - } -} - #[derive(Debug, Clone, Copy)] pub struct PixcelWriter { frame_buffer_base: *mut u8, @@ -179,6 +163,10 @@ impl PixcelInfo for PixcelWriter { fn pixcels_per_scan_line(&self) -> usize { self.pixcels_per_scan_line } + + fn frame_buffer_base(&self) -> *mut u8 { + self.frame_buffer_base + } } impl PixcelWriter @@ -200,8 +188,15 @@ pub fn get_pixcel_writer() -> Option<&'static (dyn AsciiWriter + Send + Sync)> { Some(WRITER.lock().get()?.pixcel_writer()) } +static mut GRAPHICS_INFO: GraphicsInfo = GraphicsInfo::uninitialized(); +pub fn get_graphics_info() -> &'static GraphicsInfo { + unsafe { &GRAPHICS_INFO } +} /// init graphics and return pixcel_writer pub fn init_graphics(graphics_info: GraphicsInfo) -> &'static (dyn AsciiWriter + Send + Sync) { + unsafe { + GRAPHICS_INFO = graphics_info; + } // clear for y in 0..graphics_info.vertical_resolution() { for x in 0..graphics_info.horizontal_resolution() { @@ -220,6 +215,10 @@ pub fn init_graphics(graphics_info: GraphicsInfo) -> &'static (dyn AsciiWriter + let writer = Writer::new(pixcel_writer); writer }); + kernel_lib::lock!(LAYER_MANGER).get_or_init(|| { + let layer_manager = LayerManager::new(pixcel_writer); + layer_manager + }); pixcel_writer } @@ -331,3 +330,30 @@ pub fn _print_and_flush(args: fmt::Arguments) { writer.flush(); }); } + +pub static LAYER_MANGER: Mutex>> = Mutex::new(OnceCell::new()); + +#[macro_export] +macro_rules! lock_layer_manager { + () => { + kernel_lib::lock!($crate::graphics::LAYER_MANGER) + .get() + .unwrap() + }; +} + +#[macro_export] +macro_rules! lock_layer_manager_mut { + () => { + kernel_lib::lock!($crate::graphics::LAYER_MANGER) + .get_mut() + .unwrap() + }; +} + +#[macro_export] +macro_rules! lock_layer_manager_raw { + () => { + kernel_lib::lock!($crate::graphics::LAYER_MANGER) + }; +} diff --git a/kernel/src/lifegame.rs b/kernel/src/lifegame.rs index 42aa752..5b78ded 100644 --- a/kernel/src/lifegame.rs +++ b/kernel/src/lifegame.rs @@ -4,11 +4,14 @@ use core::sync::atomic::AtomicBool; use alloc::collections::VecDeque; use alloc::vec::Vec; use kernel_lib::futures::yield_pending; +use kernel_lib::layer::{Position, Window}; use kernel_lib::mutex::Mutex; -use kernel_lib::render::Vector2D; +use kernel_lib::pixel::new_rendering_handler; +use kernel_lib::render::{RendererMut, Vector2D}; use kernel_lib::Color; -use crate::graphics::get_pixcel_writer; +use crate::graphics::get_graphics_info; +use crate::lock_layer_manager_mut; pub static CLICKED_POSITION_QUEUE: Mutex> = Mutex::new(VecDeque::new()); @@ -21,16 +24,13 @@ pub static RUNNING: AtomicBool = AtomicBool::new(true); pub fn frame_buffer_position_to_board_position( frame_buffer_position: Vector2D, ) -> Option<(usize, usize)> { - log::debug!("transforming...: {:?}", &frame_buffer_position); let x = frame_buffer_position.x as isize - BOARD_POS.x as isize; let y = frame_buffer_position.y as isize - BOARD_POS.y as isize; - log::debug!("(relative) (x, y) = {:?}", (x, y)); if x < 0 || y < 0 { return None; } let x = x as usize / PIXCEL_SIZE; let y = y as usize / PIXCEL_SIZE; - log::debug!("(x, y) = {:?}", (x, y)); if x >= SIZE || y >= SIZE { return None; } @@ -38,7 +38,15 @@ pub fn frame_buffer_position_to_board_position( } pub async fn do_lifegame() { - let pixcel_writer = get_pixcel_writer().unwrap(); + let window = Window::new( + SIZE * PIXCEL_SIZE, + SIZE * PIXCEL_SIZE, + new_rendering_handler(*get_graphics_info()), + None, + Position::new(0, 0), + ); + let id = { crate::lock_layer_manager_mut!().new_layer(window) }; + // let pixcel_writer = get_pixcel_writer().unwrap(); let board: [[u8; SIZE]; SIZE] = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -74,16 +82,28 @@ pub async fn do_lifegame() { board[y][x] = true; } if !is_empty { - pixcel_writer.render_board(&board, BOARD_POS, PIXCEL_SIZE, Color::green()); + crate::lock_layer_manager_mut!() + .layer_mut(id) + .unwrap() + .render_board(&board, BOARD_POS, PIXCEL_SIZE, Color::green()); } } yield_pending().await; } + { + crate::lock_layer_manager!().flush(); + } + yield_pending().await; // log::info!("RUNNING: {}", RUNNING.load(core::sync::atomic::Ordering::SeqCst)); if RUNNING.load(core::sync::atomic::Ordering::SeqCst) { process::(&mut board); } - pixcel_writer.render_board(&board, BOARD_POS, PIXCEL_SIZE, Color::green()); + { + lock_layer_manager_mut!() + .layer_mut(id) + .unwrap() + .render_board(&board, BOARD_POS, PIXCEL_SIZE, Color::green()); + } yield_pending().await; } } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index a3a51f4..928ea83 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -4,10 +4,10 @@ use core::{arch::asm, panic::PanicInfo}; pub extern crate alloc; -use common::types::KernelMainArg; -use core::fmt::Write; +use alloc::vec::Vec; +use common::types::{KernelMainArg, MemoryType}; use kernel::{ - alloc::alloc::GlobalAllocator, + alloc::alloc::{init_allocator, GlobalAllocator}, graphics::{init_graphics, init_logger}, interrupts::init_idt, memory::MemoryMapper, @@ -16,39 +16,88 @@ use kernel::{ task::{Priority, Task}, }, println, serial_println, - usb::{class_driver::callbacks, device::DeviceContextInfo}, + usb::{ + class_driver::callbacks::{self, init_mouse_cursor_layer}, + device::DeviceContextInfo, + }, xhci::init_xhci_controller, }; -use kernel_lib::{render::Vector2D, shapes::mouse::MOUSE_CURSOR_SHAPE, Color}; +use kernel_lib::{render::Vector2D, Color}; + +const STACK_SIZE: usize = 1024 * 1024; +#[repr(align(16))] +pub struct KernelStack([u8; STACK_SIZE]); +#[no_mangle] +static mut KERNEL_STACK: KernelStack = KernelStack([0; STACK_SIZE]); #[no_mangle] extern "C" fn kernel_main(arg: *const KernelMainArg) -> ! { - serial_println!("Hello lemola os!!! from serial"); + let end_ptr = unsafe { KERNEL_STACK.0.as_ptr_range().end }; + + unsafe { + asm!( + "mov rsp, {0}", + "call rax", + in(reg) end_ptr, + in("rax") kernel_main2 as extern "sysv64" fn(*const KernelMainArg) -> !, + in("rdi") arg, + clobber_abi("sysv64") + ) + }; + + loop { + unsafe { + asm!("hlt"); + } + } +} + +#[no_mangle] +extern "sysv64" fn kernel_main2(arg: *const KernelMainArg) -> ! { let arg = unsafe { (*arg).clone() }; let graphics_info = arg.graphics_info; let pixcel_writer = init_graphics(graphics_info); pixcel_writer.fill_rect(Vector2D::new(50, 50), Vector2D::new(50, 50), Color::white()); - println!("global WRITER initialized?"); - writeln!( - kernel_lib::lock!(kernel::graphics::WRITER.0) - .get_mut() - .unwrap(), - "Hello lemola os!!!" - ) - .unwrap(); init_logger(); log::info!("global logger initialized!"); - pixcel_writer.write_ascii(50, 50, 'A', Color::white(), Color::new(255, 50, 0)); - - pixcel_writer.fill_shape(Vector2D::new(30, 50), &MOUSE_CURSOR_SHAPE); + let memory_map_iter = unsafe { arg.memory_map_entry.as_ref().unwrap().into_iter() }; + let heap = memory_map_iter + .clone() + .filter_map(|desc| { + if let MemoryType::CONVENTIONAL + | MemoryType::BOOT_SERVICES_CODE + | MemoryType::BOOT_SERVICES_DATA = desc.ty + { + Some(desc.phys_start..(desc.phys_start + desc.page_count * 4096)) + } else { + None + } + }) + .max_by_key(|range| range.end - range.start) + .expect("no conventional memory region found"); + unsafe { + init_allocator(heap.start as usize, heap.end as usize); + } + let memory_map = memory_map_iter.collect::>(); + for desc in memory_map.iter() { + log::debug!( + "[0x{:09x} - 0x{:09x}] of type {:?}", + desc.phys_start, + desc.phys_start + desc.page_count * 4096, + desc.ty + ); + } let class_drivers = kernel::usb::class_driver::ClassDriverManager::new( callbacks::mouse(), callbacks::keyboard(), ); + unsafe { + init_mouse_cursor_layer(); + } let class_drivers: &'static _ = unsafe { &*(&class_drivers as *const _) }; let controller = init_xhci_controller(class_drivers); init_idt(); diff --git a/kernel/src/usb/class_driver/callbacks.rs b/kernel/src/usb/class_driver/callbacks.rs index d3b7a22..ceb80a1 100644 --- a/kernel/src/usb/class_driver/callbacks.rs +++ b/kernel/src/usb/class_driver/callbacks.rs @@ -1,16 +1,19 @@ use kernel_lib::{ - render::{AtomicVec2D, Vector2D}, - shapes::mouse::MOUSE_CURSOR_SHAPE, + layer::{LayerId, Position, Window}, + pixel::new_rendering_handler, + render::{RendererMut, Vector2D}, + shapes::{ + mouse::{MouseCursorPixel, MOUSE_CURSOR_SHAPE}, + Shape, + }, }; use crate::{ - graphics::get_pixcel_writer, + graphics::get_graphics_info, lifegame::{self, frame_buffer_position_to_board_position, CLICKED_POSITION_QUEUE}, print_and_flush, }; -static MOUSE_CURSOR: AtomicVec2D = AtomicVec2D::new(700, 500); - pub type CallbackType = fn(u8, &[u8]); pub const fn keyboard() -> CallbackType { @@ -21,40 +24,78 @@ pub const fn mouse() -> CallbackType { _mouse } +/// This function must be called before any other functions that use MOUSE_LAYER_ID. +/// # Safety +/// This method must be called before mouse driver is initialized. +/// Also, this method must be called only once. +pub unsafe fn init_mouse_cursor_layer() -> LayerId { + let window = Window::new( + MOUSE_CURSOR_SHAPE.get_width(), + MOUSE_CURSOR_SHAPE.get_height(), + new_rendering_handler(*get_graphics_info()), + Some(MouseCursorPixel::BackGround.into()), + Position::new(0, 0), + ); + let id = { + let mut mgr = crate::lock_layer_manager_raw!(); + let mgr = mgr.get_mut().unwrap(); + let id = mgr.new_layer(window); + mgr.move_relative(id, 0, 0); + let layer = mgr.layer_mut(id).unwrap(); + layer.fill_shape(Vector2D::new(0, 0), &MOUSE_CURSOR_SHAPE); + + id + }; + + // Safety: This function assumed to be called before any other functions that use MOUSE_LAYER_ID. + unsafe { + MOUSE_LAYER_ID = id; + }; + id +} + +static mut MOUSE_LAYER_ID: LayerId = LayerId::uninitialized(); +fn mouse_layer_id() -> LayerId { + // Safety: MOUSE_LAYER_ID is initialized by init_mouse_cursor_layer. + unsafe { MOUSE_LAYER_ID } +} + #[doc(hidden)] pub fn _mouse(_address: u8, buf: &[u8]) { let x_diff = buf[1] as i8; let y_diff = buf[2] as i8; - log::debug!("{:?}", [x_diff, y_diff]); let left_click = buf[0] & 0b1 != 0; - log::debug!("buf: {:?}, clicked: {}", buf, left_click); + let pos = { + crate::lock_layer_manager!() + .layer(mouse_layer_id()) + .unwrap() + .window() + .position() + }; + log::debug!("pos: {:?}", pos); if left_click { - let pos = MOUSE_CURSOR.into_vec(); - let pos = Vector2D::new(pos.0 as usize, pos.1 as usize); + let pos = { + crate::lock_layer_manager!() + .layer(mouse_layer_id()) + .unwrap() + .window() + .position() + }; + let pos = Vector2D::new(pos.x, pos.y); + log::debug!("pos: {:?}", pos); if let Some(pos) = frame_buffer_position_to_board_position(pos) { let mut queue = kernel_lib::lock!(CLICKED_POSITION_QUEUE); queue.push_back(pos); } } - MOUSE_CURSOR.add(x_diff as isize, y_diff as isize); - if let Some(pixcel_writer) = get_pixcel_writer() { - let (mut x, mut y) = MOUSE_CURSOR.into_vec(); - use core::cmp::{max, min}; - x = min( - max(x, 0), - pixcel_writer.horizontal_resolution() as isize - 1, + { + crate::lock_layer_manager_mut!().move_relative( + mouse_layer_id(), + x_diff.into(), + y_diff.into(), ); - y = min(max(y, 0), pixcel_writer.vertical_resolution() as isize - 1); - let vec = Vector2D::new(x as usize, y as usize); - log::debug!( - "rendering: {:?} in [{}, {}]", - vec, - pixcel_writer.horizontal_resolution(), - pixcel_writer.vertical_resolution() - ); - pixcel_writer.fill_shape(vec, &MOUSE_CURSOR_SHAPE); - }; + } } #[doc(hidden)] @@ -63,7 +104,6 @@ pub fn _keyboard(_address: u8, buf: &[u8]) { buf[1..] .iter() .filter_map(|&keycode| { - log::debug!("keycode: {}", keycode); if keycode == 0 { None } else if shifted { @@ -73,10 +113,8 @@ pub fn _keyboard(_address: u8, buf: &[u8]) { } }) .for_each(|c| { - log::debug!("char: '{}'", c); if c == ' ' { // flip the RUNNING state - log::debug!("flip"); lifegame::RUNNING.fetch_not(core::sync::atomic::Ordering::SeqCst); } print_and_flush!("{}", c) diff --git a/kernel/src/xhci.rs b/kernel/src/xhci.rs index be0c610..205f892 100644 --- a/kernel/src/xhci.rs +++ b/kernel/src/xhci.rs @@ -1,3 +1,4 @@ +extern crate alloc; use core::ffi::c_void; use kernel_lib::futures::yield_pending; @@ -37,18 +38,15 @@ where loop { { if controller.pending_already_popped_queue() { - log::debug!("having pending already popped queue"); controller.process_once_received().await; + yield_pending().await; } if controller.pending_event() { - log::debug!("having pending event"); controller.process_event().await; + yield_pending().await; } controller.process_user_event().await; - } - - for _ in 0..100 { yield_pending().await; } } diff --git a/kernel/src/xhci/controller.rs b/kernel/src/xhci/controller.rs index b181e5e..c994deb 100644 --- a/kernel/src/xhci/controller.rs +++ b/kernel/src/xhci/controller.rs @@ -17,7 +17,6 @@ use xhci::{ use crate::{ alloc::alloc::{alloc_array_with_boundary, alloc_with_boundary, GlobalAllocator}, memory::PAGE_SIZE, - serial_println, usb::{ class_driver::{keyboard, mouse, ClassDriverManager, DriverKind}, device::{DeviceContextIndex, DeviceContextInfo, InputContextWrapper}, @@ -252,10 +251,8 @@ where // EventRing does not have front return; } - log::debug!("[XHCI] EventRing received"); let primary_interrupter = primary_interrupter; let popped = event_ring.pop(primary_interrupter); - log::debug!("popped: {:x?}", popped); drop(registers); drop(event_ring); let _trb = match popped { @@ -270,6 +267,7 @@ where } pub async fn process_event_ring_event(&self, event_trb: event::Allowed) { + log::debug!("event_trb: {:?}", event_trb); match event_trb { event::Allowed::TransferEvent(transfer_event) => { self.process_transfer_event(transfer_event); @@ -1252,7 +1250,6 @@ where } fn process_transfer_event(&self, event: trb::event::TransferEvent) { - serial_println!("TransferEvent received"); match event.completion_code() { Ok(event::CompletionCode::ShortPacket | event::CompletionCode::Success) => {} Ok(code) => { @@ -1298,7 +1295,6 @@ where let buffer = normal.data_buffer_pointer() as *mut u8; let driver_kind = self.class_driver_manager.driver_kind(slot_id as usize); - log::debug!("driver_kind: {:?}", driver_kind); match driver_kind { Some(DriverKind::Mouse) => { assert_eq!( @@ -1306,8 +1302,6 @@ where mouse::N_IN_TRANSFER_BYTES as u32 ); assert_eq!(3, mouse::N_IN_TRANSFER_BYTES as u32); - log::debug!("buffer: {:p}", buffer); - log::debug!("trb_transfer_length: {}", normal.trb_transfer_length()); let address = { let device = self.usb_device_host_at(slot_id as usize); let device = kernel_lib::lock!(device); diff --git a/kernel/src/xhci/event_ring.rs b/kernel/src/xhci/event_ring.rs index 0f2a28a..c34a9c2 100644 --- a/kernel/src/xhci/event_ring.rs +++ b/kernel/src/xhci/event_ring.rs @@ -183,7 +183,6 @@ impl EventRing<&'static GlobalAllocator> { }; if next == segment_end { - log::debug!("reached segment end."); next = segment_begin; self.cycle_bit = !self.cycle_bit; } diff --git a/kernel/src/xhci/transfer_ring.rs b/kernel/src/xhci/transfer_ring.rs index 532aff9..1a9d5f9 100644 --- a/kernel/src/xhci/transfer_ring.rs +++ b/kernel/src/xhci/transfer_ring.rs @@ -71,19 +71,11 @@ impl TransferRing<&'static GlobalAllocator> { } pub fn flip_cycle_bit_at(&mut self, trb_pointer: u64) { - log::debug!( - "writing trb_ptr: {:p} in [{:p} - {:p}]", - trb_pointer as *const TrbRaw, - self.trb_buffer.as_ptr(), - unsafe { self.trb_buffer.as_ptr().add(self.trb_buffer.len()) } - ); - log::debug!("buffer_range: {:x?}", self.buffer_range()); let write_index = self .buffer_range() .position(|i| i == trb_pointer as usize) .unwrap() / core::mem::size_of::(); - log::debug!("write_index: {}", write_index); assert_ne!(write_index, self.trb_buffer.len() - 1); self.write_index = write_index; self.trb_buffer[write_index].toggle_cycle_bit(); @@ -91,7 +83,6 @@ impl TransferRing<&'static GlobalAllocator> { self.write_index += 1; if self.write_index == self.trb_buffer.len() - 1 { self.cycle_count += 1; - log::debug!("end of the ring"); // reached end of the ring let mut link = trb::Link::new(); link.set_ring_segment_pointer(self.trb_buffer.as_ptr() as u64); @@ -107,8 +98,6 @@ impl TransferRing<&'static GlobalAllocator> { self.write_index = 0; self.toggle_cycle_bit(); } - // serial_println!("cycle_count: {}", self.cycle_count); - // self.dump_state(); } pub fn buffer_range(&self) -> core::ops::Range {