diff --git a/.gitignore b/.gitignore index cd213a6..58d3fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /limine -/ovmf +/edk2-ovmf *.iso *.hdd diff --git a/GNUmakefile b/GNUmakefile index 1cc192f..673cbcf 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -26,25 +26,24 @@ run: run-$(KARCH) run-hdd: run-hdd-$(KARCH) .PHONY: run-x86_64 -run-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso +run-x86_64: edk2-ovmf $(IMAGE_NAME).iso qemu-system-$(KARCH) \ -M q35 \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -serial stdio \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -cdrom $(IMAGE_NAME).iso \ $(QEMUFLAGS) .PHONY: run-hdd-x86_64 -run-hdd-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd +run-hdd-x86_64: edk2-ovmf $(IMAGE_NAME).hdd qemu-system-$(KARCH) \ -M q35 \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -hda $(IMAGE_NAME).hdd \ $(QEMUFLAGS) .PHONY: run-aarch64 -run-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso +run-aarch64: edk2-ovmf $(IMAGE_NAME).iso qemu-system-$(KARCH) \ -M virt \ -cpu cortex-a72 \ @@ -52,13 +51,13 @@ run-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME) -device qemu-xhci \ -device usb-kbd \ -device usb-mouse \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -serial stdio \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -cdrom $(IMAGE_NAME).iso \ $(QEMUFLAGS) .PHONY: run-hdd-aarch64 -run-hdd-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd +run-hdd-aarch64: edk2-ovmf $(IMAGE_NAME).hdd qemu-system-$(KARCH) \ -M virt \ -cpu cortex-a72 \ @@ -66,13 +65,12 @@ run-hdd-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_N -device qemu-xhci \ -device usb-kbd \ -device usb-mouse \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -hda $(IMAGE_NAME).hdd \ $(QEMUFLAGS) .PHONY: run-riscv64 -run-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso +run-riscv64: edk2-ovmf $(IMAGE_NAME).iso qemu-system-$(KARCH) \ -M virt \ -cpu rv64 \ @@ -80,13 +78,12 @@ run-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME) -device qemu-xhci \ -device usb-kbd \ -device usb-mouse \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -cdrom $(IMAGE_NAME).iso \ $(QEMUFLAGS) .PHONY: run-hdd-riscv64 -run-hdd-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd +run-hdd-riscv64: edk2-ovmf $(IMAGE_NAME).hdd qemu-system-$(KARCH) \ -M virt \ -cpu rv64 \ @@ -94,13 +91,12 @@ run-hdd-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_N -device qemu-xhci \ -device usb-kbd \ -device usb-mouse \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -hda $(IMAGE_NAME).hdd \ $(QEMUFLAGS) .PHONY: run-loongarch64 -run-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso +run-loongarch64: edk2-ovmf $(IMAGE_NAME).iso qemu-system-$(KARCH) \ -M virt \ -cpu la464 \ @@ -108,13 +104,12 @@ run-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_N -device qemu-xhci \ -device usb-kbd \ -device usb-mouse \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -cdrom $(IMAGE_NAME).iso \ $(QEMUFLAGS) .PHONY: run-hdd-loongarch64 -run-hdd-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd +run-hdd-loongarch64: edk2-ovmf $(IMAGE_NAME).hdd qemu-system-$(KARCH) \ -M virt \ -cpu la464 \ @@ -122,8 +117,7 @@ run-hdd-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMA -device qemu-xhci \ -device usb-kbd \ -device usb-mouse \ - -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ - -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ + -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -hda $(IMAGE_NAME).hdd \ $(QEMUFLAGS) @@ -143,27 +137,12 @@ run-hdd-bios: $(IMAGE_NAME).hdd -hda $(IMAGE_NAME).hdd \ $(QEMUFLAGS) -ovmf/ovmf-code-$(KARCH).fd: - mkdir -p ovmf - curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-code-$(KARCH).fd - case "$(KARCH)" in \ - aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \ - loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \ - riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \ - esac - -ovmf/ovmf-vars-$(KARCH).fd: - mkdir -p ovmf - curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-vars-$(KARCH).fd - case "$(KARCH)" in \ - aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \ - loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \ - riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \ - esac +edk2-ovmf: + curl -L https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/edk2-ovmf.tar.gz | gunzip | tar -xf - limine/limine: rm -rf limine - git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 + git clone https://github.com/limine-bootloader/limine.git --branch=v10.x-binary --depth=1 $(MAKE) -C limine .PHONY: kernel @@ -213,7 +192,6 @@ ifeq ($(KARCH),loongarch64) iso_root -o $(IMAGE_NAME).iso endif rm -rf iso_root - qemu-system-$(KARCH) -cdrom $(IMAGE_NAME).iso -m 1G -serial stdio $(IMAGE_NAME).hdd: limine/limine kernel rm -f $(IMAGE_NAME).hdd diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 69a0fa6..ae6aefb 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -6,6 +6,7 @@ version = 4 name = "XunilOS" version = "0.1.0" dependencies = [ + "aarch64-cpu", "font8x8", "heapless", "lazy_static", @@ -17,6 +18,15 @@ dependencies = [ "x86_64", ] +[[package]] +name = "aarch64-cpu" +version = "11.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44171e22925ec72b63d86747bc3655c7849a5b8d865c980222128839f45ac034" +dependencies = [ + "tock-registers", +] + [[package]] name = "bit_field" version = "0.10.3" @@ -156,6 +166,12 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "tock-registers" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2d250f87fb3fb6f225c907cf54381509f47b40b74b1d1f12d2dccbc915bdfe" + [[package]] name = "volatile" version = "0.4.6" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 572c9bb..adf905c 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -14,13 +14,16 @@ heapless = "0.9.2" lazy_static = { version = "1.5.0", features = ["spin_no_std"] } limine = "0.5" pc-keyboard = "0.8.0" -pic8259 = "0.11.0" spin = "0.10.0" static_cell = "2.1.1" [target.'cfg(target_arch = "x86_64")'.dependencies] +pic8259 = "0.11.0" x86_64 = "0.15.4" +[target.'cfg(target_arch = "aarch64")'.dependencies] +aarch64-cpu = "11.2.0" + [profile.dev] panic = "abort" diff --git a/kernel/rust-toolchain.toml b/kernel/rust-toolchain.toml index 66a0077..56129dc 100644 --- a/kernel/rust-toolchain.toml +++ b/kernel/rust-toolchain.toml @@ -1,8 +1,8 @@ [toolchain] channel = "nightly" targets = [ - "x86_64-unknown-none", - # "aarch64-unknown-none", + # "x86_64-unknown-none", + "aarch64-unknown-none", # "riscv64gc-unknown-none-elf", # "loongarch64-unknown-none", ] diff --git a/kernel/src/arch/aarch64/heap.rs b/kernel/src/arch/aarch64/heap.rs new file mode 100644 index 0000000..9dea8dd --- /dev/null +++ b/kernel/src/arch/aarch64/heap.rs @@ -0,0 +1,3 @@ +use crate::{mm::heap::LinkedListAllocator, util::Locked}; +#[global_allocator] +pub static ALLOCATOR: Locked = Locked::new(LinkedListAllocator::new()); diff --git a/kernel/src/arch/aarch64/init.rs b/kernel/src/arch/aarch64/init.rs new file mode 100644 index 0000000..1cd0f1e --- /dev/null +++ b/kernel/src/arch/aarch64/init.rs @@ -0,0 +1,2 @@ +use limine::response::{HhdmResponse, MemoryMapResponse}; +pub fn init_aarch64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {} diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs new file mode 100644 index 0000000..c79cb30 --- /dev/null +++ b/kernel/src/arch/aarch64/mod.rs @@ -0,0 +1,3 @@ +pub mod heap; +pub mod init; +pub mod paging; diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs new file mode 100644 index 0000000..e9eb83c --- /dev/null +++ b/kernel/src/arch/aarch64/paging.rs @@ -0,0 +1,5 @@ +use crate::arch::arch::XunilFrameAllocator; +use spin::Mutex; + +pub static FRAME_ALLOCATOR_AARCH64: Mutex = + Mutex::new(XunilFrameAllocator::new()); diff --git a/kernel/src/arch/arch.rs b/kernel/src/arch/arch.rs index 5292fb9..81edc73 100644 --- a/kernel/src/arch/arch.rs +++ b/kernel/src/arch/arch.rs @@ -1,16 +1,85 @@ #[cfg(target_arch = "x86_64")] pub use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64 as FRAME_ALLOCATOR; -use crate::driver::timer::TIMER; -use core::{alloc::GlobalAlloc, arch::asm}; -use limine::response::{HhdmResponse, MemoryMapResponse}; +#[cfg(target_arch = "aarch64")] +pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR; + +use crate::{driver::timer::TIMER, util::align_up}; +use core::arch::asm; +use limine::{ + memory_map::{Entry, EntryType}, + response::{HhdmResponse, MemoryMapResponse}, +}; + +#[derive(Clone, Copy)] +#[allow(dead_code)] +pub struct UsableRegion { + pub base: u64, + pub length: u64, +} + +const EMPTY_REGION: UsableRegion = UsableRegion { base: 0, length: 0 }; + +// NOTE: dont change name to frameallocator as that is the name of the trait of x86_64 +pub struct XunilFrameAllocator { + pub hhdm_offset: u64, + pub usable_regions: [UsableRegion; 1024], + pub usable_region_count: usize, + pub region_index: usize, + pub region_offset: usize, +} + +impl XunilFrameAllocator { + pub const fn new() -> Self { + Self { + hhdm_offset: 0, + usable_regions: [EMPTY_REGION; 1024], + usable_region_count: 0, + region_index: 0, + region_offset: 0, + } + } + + pub fn initialize(&mut self, hhdm_offset: u64, memory_map: &[&Entry]) { + let mut regions = [EMPTY_REGION; 1024]; + let mut count = 0usize; + + for region in memory_map.iter().copied() { + if region.entry_type != EntryType::USABLE { + continue; + } + + if count < regions.len() && region.length >= 4096 { + let aligned_base = align_up(region.base, 4096); + let base_offset = aligned_base - region.base; + let aligned_length = region.length.saturating_sub(base_offset); + if aligned_length >= 4096 { + regions[count] = UsableRegion { + base: aligned_base, + length: aligned_length, + }; + count += 1; + } + } + } + + self.hhdm_offset = hhdm_offset; + self.usable_regions = regions; + self.usable_region_count = count; + self.region_index = 0; + self.region_offset = 0; + } +} #[cfg(target_arch = "x86_64")] use crate::arch::x86_64::{ - elf::run_elf_x86_64, heap::ALLOCATOR, init::init_x86_64, usermode::enter_usermode_x86_64, + elf::run_elf_x86_64, init::init_x86_64, usermode::enter_usermode_x86_64, }; #[cfg(target_arch = "x86_64")] -use x86_64::structures::paging::OffsetPageTable; +use x86_64::{instructions::interrupts::without_interrupts, structures::paging::OffsetPageTable}; + +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::init::init_aarch64; #[cfg(target_arch = "x86_64")] pub fn init<'a>( @@ -20,18 +89,36 @@ pub fn init<'a>( return init_x86_64(hhdm_response, memory_map_response); } +#[cfg(target_arch = "aarch64")] +pub fn init<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) { + return init_aarch64(hhdm_response, memory_map_response); +} + #[cfg(target_arch = "x86_64")] pub fn enter_usermode(user_rip: u64, user_rsp: u64, should_swapgs: bool) { enter_usermode_x86_64(user_rip, user_rsp, should_swapgs); } +#[cfg(target_arch = "aarch64")] +pub fn enter_usermode(user_rip: u64, user_rsp: u64, should_swapgs: bool) { + unimplemented!() +} + #[cfg(target_arch = "x86_64")] pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) { run_elf_x86_64(file_bytes, should_swapgs); } -pub fn get_allocator<'a>() -> &'static impl GlobalAlloc { - return &ALLOCATOR; +#[cfg(target_arch = "aarch64")] +pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) { + unimplemented!() +} + +pub fn safe_lock R>(f: F) -> R { + #[cfg(target_arch = "x86_64")] + return without_interrupts(|| f()); + #[cfg(target_arch = "aarch64")] + return f(); } pub fn idle() { diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs index fba1b6e..9b81f54 100644 --- a/kernel/src/arch/mod.rs +++ b/kernel/src/arch/mod.rs @@ -1,4 +1,7 @@ -pub mod arch; -pub mod syscall; +#[cfg(target_arch = "aarch64")] +pub mod aarch64; #[cfg(target_arch = "x86_64")] pub mod x86_64; + +pub mod arch; +pub mod syscall; diff --git a/kernel/src/arch/syscall.rs b/kernel/src/arch/syscall.rs index 2a8d7ef..7039c7c 100644 --- a/kernel/src/arch/syscall.rs +++ b/kernel/src/arch/syscall.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] use alloc::vec; +#[cfg(target_arch = "x86_64")] use x86_64::{ PhysAddr, VirtAddr, instructions::interrupts, @@ -15,7 +16,6 @@ use crate::{ keyboard::{KeyboardEvent, process_scancodes}, timer::TIMER, }, - mm::usercopy::{copy_cstr_from_user, copy_to_user}, print, task::{ process::ProcessState, @@ -24,6 +24,12 @@ use crate::{ util::{align_down, align_up}, }; +#[cfg(target_arch = "x86_64")] +use crate::{ + arch::arch::safe_lock, + mm::usercopy::{copy_cstr_from_user, copy_to_user}, +}; + const READ: usize = 0; const WRITE: usize = 1; const OPEN: usize = 2; @@ -50,6 +56,7 @@ const SLEEP: usize = 909090; // zzz haha pub const MAP_FRAMEBUFFER: usize = 5555; pub const FRAMEBUFFER_SWAP: usize = 6666; +#[cfg(target_arch = "x86_64")] fn map_framebuffer() -> isize { let pid = current_pid().unwrap_or(0); if pid == 0 { @@ -107,6 +114,12 @@ fn map_framebuffer() -> isize { .unwrap_or(-1) } +#[cfg(target_arch = "aarch64")] +fn map_framebuffer() -> isize { + 0 +} + +#[cfg(target_arch = "x86_64")] fn read(ptr: isize, size: isize, nmemb: isize, fd: isize) -> isize { let pid = current_pid().unwrap_or(0); if pid == 0 { @@ -142,6 +155,12 @@ fn read(ptr: isize, size: isize, nmemb: isize, fd: isize) -> isize { .unwrap_or(-1) } +#[cfg(target_arch = "aarch64")] +fn read(ptr: isize, size: isize, nmemb: isize, fd: isize) -> isize { + 0 +} + +#[cfg(target_arch = "x86_64")] fn open(path: isize, mode: isize) -> isize { let pid = current_pid().unwrap_or(0); if pid == 0 { @@ -160,10 +179,16 @@ fn open(path: isize, mode: isize) -> isize { .unwrap_or(-1) } +#[cfg(target_arch = "aarch64")] +fn open(path: isize, mode: isize) -> isize { + 0 +} + fn close(fd: isize) -> isize { vfs_close(fd as i64) as isize } +#[cfg(target_arch = "x86_64")] fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize { process_scancodes(); if max_events <= 0 || user_ptr.is_null() { @@ -198,6 +223,12 @@ fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize { .unwrap_or(-1); } +#[cfg(target_arch = "aarch64")] +fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize { + 0 +} + +#[cfg(target_arch = "x86_64")] pub unsafe fn sbrk(increment: isize) -> isize { let pid = current_pid().unwrap_or(0); @@ -205,9 +236,10 @@ pub unsafe fn sbrk(increment: isize) -> isize { return -1; } - let mut frame_allocator = FRAME_ALLOCATOR.lock(); return SCHEDULER .with_process(pid as u64, |process| { + let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR.lock()); + let (heap_end, heap_base, stack_top) = (process.heap_end, process.heap_base, process.stack_top); @@ -223,8 +255,8 @@ pub unsafe fn sbrk(increment: isize) -> isize { if new < heap_base { return -1; } - if new > stack_top - 16384 * 4096 { - // 67 mib max + if new > stack_top - 65535 * 4096 { + // 262 mib max return -1; } @@ -272,6 +304,12 @@ pub unsafe fn sbrk(increment: isize) -> isize { .unwrap_or(-1); } +#[cfg(target_arch = "aarch64")] +pub unsafe fn sbrk(increment: isize) -> isize { + 0 +} + +#[cfg(target_arch = "x86_64")] pub fn exec(arg0: isize) -> isize { let pid = current_pid().unwrap_or(0); if pid == 0 { @@ -336,6 +374,11 @@ pub fn exec(arg0: isize) -> isize { 0 } +#[cfg(target_arch = "aarch64")] +pub fn exec(arg0: isize) -> isize { + 0 +} + pub fn set_reschedule(should_reschedule: bool) { let pid = current_pid().unwrap_or(0); @@ -352,6 +395,43 @@ pub fn set_reschedule(should_reschedule: bool) { drop(scheduler); } +#[cfg(target_arch = "x86_64")] +pub fn exit() -> isize { + let pid = current_pid().unwrap_or(0); + if pid == 0 { + return 0; + } + + let next_pid = { + let mut sched = SCHEDULER.lock(); + + sched.processes.remove(&pid); + + sched + .processes + .iter() + .find_map(|(other, proc)| { + if *other != pid && matches!(proc.state, ProcessState::Ready) { + Some(*other) + } else { + None + } + }) + .unwrap_or(0) + }; + + if next_pid != 0 { + SCHEDULER.switch_to(next_pid, false); + } + + crate::arch::arch::infinite_idle(); +} + +#[cfg(target_arch = "aarch64")] +pub fn exit() -> isize { + 0 +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn syscall_dispatch( num: usize, @@ -362,6 +442,7 @@ pub unsafe extern "C" fn syscall_dispatch( arg4: isize, arg5: isize, ) -> isize { + #[cfg(target_arch = "x86_64")] interrupts::enable(); set_reschedule(match num { @@ -405,36 +486,7 @@ pub unsafe extern "C" fn syscall_dispatch( OPEN => open(arg0, arg1), CLOSE => close(arg0), LSEEK => vfs_lseek(arg0 as i64, arg1 as i64, arg2 as i32) as isize, - EXIT => { - let pid = current_pid().unwrap_or(0); - if pid == 0 { - return 0; - } - - let next_pid = { - let mut sched = SCHEDULER.lock(); - - sched.processes.remove(&pid); - - sched - .processes - .iter() - .find_map(|(other, proc)| { - if *other != pid && matches!(proc.state, ProcessState::Ready) { - Some(*other) - } else { - None - } - }) - .unwrap_or(0) - }; - - if next_pid != 0 { - SCHEDULER.switch_to(next_pid, false); - } - - crate::arch::arch::infinite_idle(); - } + EXIT => exit(), SLEEP => { sleep(arg0 as u64); 0 diff --git a/kernel/src/arch/x86_64/elf.rs b/kernel/src/arch/x86_64/elf.rs index 025f3f9..6d157b0 100644 --- a/kernel/src/arch/x86_64/elf.rs +++ b/kernel/src/arch/x86_64/elf.rs @@ -26,12 +26,10 @@ pub fn run_elf_x86_64(file_bytes: &[u8], should_swapgs: bool) { .spawn_process(entry_point as u64, stack_top, heap_base) .unwrap(); - let mut frames: Vec> = Vec::new(); let mut frame_allocator = FRAME_ALLOCATOR.lock(); for i in 0..page_count { let frame = frame_allocator.allocate_frame().unwrap(); - frames.push(frame); let virt_addr = VirtAddr::new(stack_base + i as u64 * page_size); let page = Page::::containing_address(virt_addr); diff --git a/kernel/src/arch/x86_64/heap.rs b/kernel/src/arch/x86_64/heap.rs index 94f05ce..4c7db58 100644 --- a/kernel/src/arch/x86_64/heap.rs +++ b/kernel/src/arch/x86_64/heap.rs @@ -1,9 +1,5 @@ -use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64; use crate::util::Locked; -use core::{ - alloc::{GlobalAlloc, Layout}, - ptr::null_mut, -}; +use crate::{arch::x86_64::paging::FRAME_ALLOCATOR_X86_64, mm::heap::LinkedListAllocator}; use x86_64::{ VirtAddr, structures::paging::{ @@ -12,150 +8,12 @@ use x86_64::{ }, }; -fn align_up(addr: usize, align: usize) -> usize { - (addr + align - 1) & !(align - 1) -} - #[global_allocator] pub static ALLOCATOR: Locked = Locked::new(LinkedListAllocator::new()); pub const HEAP_START: usize = 0xffffffff90000000; pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MiB -pub struct LinkedNode { - pub size: usize, - pub next: Option<&'static mut LinkedNode>, -} - -impl LinkedNode { - pub const fn new(size: usize) -> LinkedNode { - LinkedNode { size, next: None } - } - - pub fn start_addr(&self) -> usize { - self as *const Self as usize - } - - pub fn end_addr(&self) -> usize { - self.start_addr() + self.size - } -} - -pub struct LinkedListAllocator { - head: LinkedNode, -} - -impl LinkedListAllocator { - pub const fn new() -> LinkedListAllocator { - Self { - head: LinkedNode::new(0), - } - } - - fn size_align(layout: Layout) -> (usize, usize) { - let layout = layout - .align_to(16) - .expect("Align to LinkedNode failed") - .pad_to_align(); - - let size = layout.size().max(core::mem::size_of::()); // either take layout's size or atleast the size of a single linked node. - - (size, layout.align()) - } - - pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { - unsafe { - self.add_free_memory_region(heap_start, heap_size); - } - } - - unsafe fn add_free_memory_region(&mut self, start: usize, size: usize) { - assert_eq!(align_up(start, 16), start); // Check if we are up at least 1 LinkedNode size - assert!(size >= core::mem::size_of::()); // check if we have enough space for a LinkedNode - - let mut linked_node = LinkedNode::new(size); - linked_node.next = self.head.next.take(); - - let linked_node_ptr = start as *mut LinkedNode; // Treat the start memory region as a LinkedNode type - unsafe { - linked_node_ptr.write(linked_node); // write the data, very risky - self.head.next = Some(&mut *linked_node_ptr); - } - } - - fn find_region( - &mut self, - size: usize, - align: usize, - ) -> Option<(&'static mut LinkedNode, usize)> { - let mut current = &mut self.head; - - while let Some(ref mut region) = current.next { - if let Ok(alloc_start) = Self::alloc_from_region(®ion, size, align) { - let next = region.next.take(); - let ret = Some((current.next.take().unwrap(), alloc_start)); - current.next = next; - - return ret; - } else { - current = current.next.as_mut().unwrap(); - } - } - - None - } - - fn alloc_from_region(region: &LinkedNode, size: usize, align: usize) -> Result { - let alloc_start = align_up(region.start_addr(), align); - let alloc_end = alloc_start.checked_add(size).ok_or(())?; // check for overflows - - if alloc_end > region.end_addr() { - return Err(()); - } - - let excess_size = region.end_addr() - alloc_end; - if excess_size > 0 && excess_size < core::mem::size_of::() { - // if the remaining space is not enough for another LinkedNode, skip this region. - return Err(()); - } - - Ok(alloc_start) - } -} - -unsafe impl GlobalAlloc for Locked { - unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - let (size, align) = LinkedListAllocator::size_align(_layout); - let mut allocator = self.lock(); - - if let Some((region, alloc_start)) = allocator.find_region(size, align) { - let alloc_end = alloc_start.checked_add(size).expect("overflow"); - - let excess_size = region.end_addr() - alloc_end; - - if excess_size > 0 { - unsafe { - allocator.add_free_memory_region(alloc_end, excess_size); - } - } - - drop(allocator); - - alloc_start as *mut u8 - } else { - null_mut() - } - } - - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { - let (size, _) = LinkedListAllocator::size_align(_layout); - - unsafe { - self.lock().add_free_memory_region(_ptr as usize, size); - } - } -} - pub fn init_heap(mapper: &mut OffsetPageTable) -> Result<(), MapToError> { let page_range = { let page_start = VirtAddr::new(HEAP_START as u64); diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs index 9c73e29..2e0a801 100644 --- a/kernel/src/arch/x86_64/paging.rs +++ b/kernel/src/arch/x86_64/paging.rs @@ -5,9 +5,7 @@ use x86_64::{ structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB}, }; -use limine::memory_map::{Entry, EntryType}; - -use crate::util::align_up; +use crate::arch::arch::XunilFrameAllocator; unsafe fn active_level_4_table(mem_offset: VirtAddr) -> &'static mut PageTable { let (level_4_table, _) = Cr3::read(); @@ -26,64 +24,6 @@ pub unsafe fn initialize_paging(physical_memory_offset: VirtAddr) -> OffsetPageT } } -#[derive(Clone, Copy)] -struct UsableRegion { - base: u64, - length: u64, -} - -const EMPTY_REGION: UsableRegion = UsableRegion { base: 0, length: 0 }; - -pub struct XunilFrameAllocator { - pub hhdm_offset: u64, - usable_regions: [UsableRegion; 1024], - usable_region_count: usize, - region_index: usize, - region_offset: usize, -} - -impl XunilFrameAllocator { - pub const fn new() -> Self { - Self { - hhdm_offset: 0, - usable_regions: [EMPTY_REGION; 1024], - usable_region_count: 0, - region_index: 0, - region_offset: 0, - } - } - - pub fn initialize(&mut self, hhdm_offset: u64, memory_map: &[&Entry]) { - let mut regions = [EMPTY_REGION; 1024]; - let mut count = 0usize; - - for region in memory_map.iter().copied() { - if region.entry_type != EntryType::USABLE { - continue; - } - - if count < regions.len() && region.length >= 4096 { - let aligned_base = align_up(region.base, 4096); - let base_offset = aligned_base - region.base; - let aligned_length = region.length.saturating_sub(base_offset); - if aligned_length >= 4096 { - regions[count] = UsableRegion { - base: aligned_base, - length: aligned_length, - }; - count += 1; - } - } - } - - self.hhdm_offset = hhdm_offset; - self.usable_regions = regions; - self.usable_region_count = count; - self.region_index = 0; - self.region_offset = 0; - } -} - unsafe impl FrameAllocator for XunilFrameAllocator { fn allocate_frame(&mut self) -> Option> { while self.region_index < self.usable_region_count { @@ -93,6 +33,11 @@ unsafe impl FrameAllocator for XunilFrameAllocator { if self.region_offset < frame_count as usize { let addr = region.base + (self.region_offset as u64 * 4096); self.region_offset += 1; + + unsafe { + core::ptr::write_bytes((addr + self.hhdm_offset) as *mut u8, 0, 4096); + } + return Some(PhysFrame::containing_address(PhysAddr::new(addr))); } diff --git a/kernel/src/driver/elf/loader.rs b/kernel/src/driver/elf/loader.rs index b98387e..b97ab48 100644 --- a/kernel/src/driver/elf/loader.rs +++ b/kernel/src/driver/elf/loader.rs @@ -1,13 +1,43 @@ use core::ptr::null; +#[cfg(target_arch = "x86_64")] +use crate::driver::elf::{ + header::{ + EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_X86_64, ET_DYN, ET_EXEC, ET_REL, Elf64Ehdr, + }, + program::load_program, +}; +#[cfg(target_arch = "x86_64")] use x86_64::structures::paging::OffsetPageTable; -use crate::driver::elf::{ - header::{ET_DYN, ET_EXEC, ET_REL, Elf64Ehdr}, - program::load_program, - validation::validate_elf, -}; +#[cfg(target_arch = "x86_64")] +pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool { + #[cfg(target_arch = "x86_64")] + let required_machine = EM_X86_64; + #[cfg(target_arch = "aarch64")] + use crate::driver::elf::header::EM_AARCH64; + #[cfg(target_arch = "aarch64")] + let required_machine = EM_AARCH64; + + elf_header.e_ident[0..4] == ELF_MAGIC + // 64 bit + && elf_header.e_ident[EI_CLASS] == 2 + // little-endian + && elf_header.e_ident[EI_DATA] == 1 + && elf_header.e_ident[EI_VERSION] == 1 + && elf_header.e_version == 1 + // check architecture + && elf_header.e_machine == required_machine + // disallow object files + && [ET_DYN, ET_EXEC].contains(&elf_header.e_type) + // standard elf64 + && elf_header.e_phentsize == 56 + && elf_header.e_phnum != 0 // zero program headers + && (elf_header.e_phoff + (elf_header.e_phnum*elf_header.e_phentsize) as u64) <= elf_len as u64 +} + +#[cfg(target_arch = "x86_64")] pub fn load_file(mapper: &mut OffsetPageTable, elf_bytes: &[u8]) -> (*const u8, u64) { // elf header size if elf_bytes.len() < 64 { diff --git a/kernel/src/driver/elf/mod.rs b/kernel/src/driver/elf/mod.rs index d9afbad..76a1b4d 100644 --- a/kernel/src/driver/elf/mod.rs +++ b/kernel/src/driver/elf/mod.rs @@ -1,4 +1,3 @@ mod header; pub mod loader; mod program; -pub mod validation; diff --git a/kernel/src/driver/elf/program.rs b/kernel/src/driver/elf/program.rs index 4da1486..9e3b1e9 100644 --- a/kernel/src/driver/elf/program.rs +++ b/kernel/src/driver/elf/program.rs @@ -1,6 +1,7 @@ +use alloc::vec::Vec; use core::ptr::{null, null_mut}; -use alloc::vec::Vec; +#[cfg(target_arch = "x86_64")] use x86_64::{ VirtAddr, structures::paging::{ @@ -29,6 +30,7 @@ pub fn get_vaddr(phdr: *const Elf64Phdr, load_bias: u64) -> *mut u8 { unsafe { ((*phdr).p_vaddr + load_bias) as *mut u8 } } +#[cfg(target_arch = "x86_64")] pub unsafe fn load_program( mapper: &mut OffsetPageTable, hdr: *const Elf64Ehdr, @@ -53,6 +55,7 @@ pub unsafe fn load_program( if !pie { for program_header in program_headers { + #[cfg(target_arch = "x86_64")] load_segment_to_memory(mapper, program_header, elf_bytes, 0); } @@ -95,6 +98,7 @@ pub unsafe fn load_program( } for program_header in program_headers { + #[cfg(target_arch = "x86_64")] load_segment_to_memory(mapper, program_header, elf_bytes, load_bias); } @@ -275,6 +279,7 @@ fn parse_dyn( ); } +#[cfg(target_arch = "x86_64")] pub fn load_segment_to_memory( mapper: &mut OffsetPageTable, phdr: *const Elf64Phdr, diff --git a/kernel/src/driver/elf/validation.rs b/kernel/src/driver/elf/validation.rs deleted file mode 100644 index c3a4e37..0000000 --- a/kernel/src/driver/elf/validation.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::driver::elf::header::{ - EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_X86_64, ET_DYN, ET_EXEC, Elf64Ehdr, -}; - -pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool { - #[allow(unused_mut)] - let mut required_machine = EM_X86_64; - #[cfg(target_arch = "aarch64")] - { - use crate::driver::elf::header::EM_AARCH64; - required_machine = EM_AARCH64; - } - - elf_header.e_ident[0..4] == ELF_MAGIC - // 64 bit - && elf_header.e_ident[EI_CLASS] == 2 - // little-endian - && elf_header.e_ident[EI_DATA] == 1 - && elf_header.e_ident[EI_VERSION] == 1 - && elf_header.e_version == 1 - // check architecture - && elf_header.e_machine == required_machine - // disallow object files - && [ET_DYN, ET_EXEC].contains(&elf_header.e_type) - // standard elf64 - && elf_header.e_phentsize == 56 - && elf_header.e_phnum != 0 // zero program headers - && (elf_header.e_phoff + (elf_header.e_phnum*elf_header.e_phentsize) as u64) <= elf_len as u64 -} diff --git a/kernel/src/driver/graphics/framebuffer.rs b/kernel/src/driver/graphics/framebuffer.rs index 69138f4..ce47277 100644 --- a/kernel/src/driver/graphics/framebuffer.rs +++ b/kernel/src/driver/graphics/framebuffer.rs @@ -1,11 +1,7 @@ use limine::framebuffer::Framebuffer as LimineFramebuffer; use spin::Mutex; -#[cfg(target_arch = "x86_64")] -use x86_64::instructions::interrupts::without_interrupts; -use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB}; - -use crate::arch::arch::FRAME_ALLOCATOR; +use crate::arch::arch::safe_lock; #[repr(C)] pub struct UserFrameBuffer { @@ -37,11 +33,35 @@ impl Framebuffer { let width = limine_fb.width() as usize; let height = limine_fb.height() as usize; let pitch = limine_fb.pitch() as usize / 4; - let buf_len = pitch * height; + + Framebuffer { + addr: limine_fb.addr().cast::(), + width, + height, + pitch, + user_fb: UserFrameBuffer { + buf_virt: 0 as *mut u32, + width, + height, + pitch, + }, + meta: FramebufferMeta { + buf_phys: 0, + buf_len: 0, + struct_phys: 0, + }, + } + } + + #[cfg(target_arch = "x86_64")] + pub fn setup_x86_64(&mut self) { + use crate::arch::arch::FRAME_ALLOCATOR; + use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB}; + let buf_len = self.pitch * self.height; let byte_len = buf_len * core::mem::size_of::(); let pixel_frames = (byte_len + 4095) / 4096; - let mut fa = FRAME_ALLOCATOR.lock(); + let mut fa = safe_lock(|| FRAME_ALLOCATOR.lock()); let struct_frame: PhysFrame = fa.allocate_frame().expect("framebuffer struct frame"); @@ -62,29 +82,16 @@ impl Framebuffer { unsafe { struct_virt.write(UserFrameBuffer { buf_virt: (USER_FB_BASE + 0x1000) as *mut u32, - width, - height, - pitch, + width: self.width, + height: self.height, + pitch: self.pitch, }); - } + }; - Framebuffer { - addr: limine_fb.addr().cast::(), - width, - height, - pitch, - user_fb: UserFrameBuffer { - buf_virt: buf_virt_kernel, - width, - height, - pitch, - }, - meta: FramebufferMeta { - buf_phys, - buf_len, - struct_phys, - }, - } + self.user_fb.buf_virt = buf_virt_kernel; + self.meta.buf_phys = buf_phys; + self.meta.buf_len = buf_len; + self.meta.struct_phys = struct_phys; } #[inline(always)] @@ -136,7 +143,7 @@ pub fn init_framebuffer(raw: &LimineFramebuffer) { } pub fn with_framebuffer(f: F) { - without_interrupts(|| { + safe_lock(|| { let mut guard = FRAMEBUFFER.lock(); if let Some(fb) = guard.as_mut() { f(fb); diff --git a/kernel/src/driver/keyboard.rs b/kernel/src/driver/keyboard.rs index f587364..4dba619 100644 --- a/kernel/src/driver/keyboard.rs +++ b/kernel/src/driver/keyboard.rs @@ -3,7 +3,7 @@ use heapless::spsc::{Consumer, Producer, Queue}; use pc_keyboard::{DecodedKey, HandleControl, KeyState, Keyboard, ScancodeSet2, layouts}; use static_cell::StaticCell; -use crate::task::scheduler::{SCHEDULER, current_pid}; +use crate::task::scheduler::SCHEDULER; #[repr(C)] #[derive(Clone, Debug, Copy, Default)] pub struct KeyboardEvent { diff --git a/kernel/src/driver/serial.rs b/kernel/src/driver/serial.rs index 2b77598..8584f80 100644 --- a/kernel/src/driver/serial.rs +++ b/kernel/src/driver/serial.rs @@ -1,13 +1,10 @@ use crate::driver::graphics::font_render::render_text; use crate::driver::graphics::framebuffer::Framebuffer; -use crate::{driver::graphics::base::rgb, util::serial_print}; +use crate::{arch::arch::safe_lock, driver::graphics::base::rgb}; use alloc::string::String; use core::fmt::{self, Write}; use spin::Mutex; -#[cfg(target_arch = "x86_64")] -use x86_64::instructions::interrupts::without_interrupts; - pub struct ConsoleWriter<'a> { pub fb: &'a mut Framebuffer, pub console: &'a mut SerialConsole, @@ -16,7 +13,6 @@ pub struct ConsoleWriter<'a> { impl Write for ConsoleWriter<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { - serial_print(s); self.console.print(s, self.fb); Ok(()) } @@ -67,10 +63,10 @@ pub fn init_serial_console() { } pub fn with_serial_console(f: F) { - without_interrupts(|| { + safe_lock(|| { let mut guard = SERIAL_CONSOLE.lock(); - if let Some(fb) = guard.as_mut() { - f(fb); + if let Some(sc) = guard.as_mut() { + f(sc); } }); } diff --git a/kernel/src/driver/timer.rs b/kernel/src/driver/timer.rs index ab150cd..393086e 100644 --- a/kernel/src/driver/timer.rs +++ b/kernel/src/driver/timer.rs @@ -27,17 +27,6 @@ impl Timer { } pub fn interrupt(&self) { - let mut scheduler = without_interrupts(|| SCHEDULER.lock()); - for process in scheduler.processes.values_mut() { - if let Some(wake_tick) = process.info.wake_tick { - if self.interrupt_count.load(Ordering::Relaxed) >= wake_tick { - process.info.wake_tick = None; - process.state = crate::task::process::ProcessState::Ready; - } - } - } - drop(scheduler); - self.interrupt_count.fetch_add(1, Ordering::Relaxed); } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 0d293e2..99b9992 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -1,14 +1,14 @@ #![no_std] #![no_main] -#![feature(abi_x86_interrupt)] +#![cfg_attr(target_arch = "x86_64", feature(abi_x86_interrupt))] #![feature(naked_functions_rustic_abi)] extern crate alloc; use core::fmt::Write; use limine::BaseRevision; use limine::request::{ - DateAtBootRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, MpRequest, - RequestsEndMarker, RequestsStartMarker, + DateAtBootRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, RequestsEndMarker, + RequestsStartMarker, }; pub mod arch; pub mod driver; @@ -22,6 +22,7 @@ use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer}; use crate::driver::keyboard::init_keyboard; use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console}; use crate::driver::timer::TIMER; +use crate::util::serial_print; #[repr(C, align(16))] struct AlignedElf([u8; include_bytes!("../../assets/init").len()]); @@ -52,10 +53,6 @@ static MEMORY_MAP_REQUEST: MemoryMapRequest = MemoryMapRequest::new(); #[unsafe(link_section = ".requests")] static DATE_AT_BOOT_REQUEST: DateAtBootRequest = DateAtBootRequest::new(); -#[used] -#[unsafe(link_section = ".requests")] -static MP_REQUEST: MpRequest = MpRequest::new(); - /// Define the stand and end markers for Limine requests. #[used] #[unsafe(link_section = ".requests_start_marker")] @@ -114,6 +111,8 @@ unsafe extern "C" fn kmain() -> ! { if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() { init_framebuffer(&limine_framebuffer); + #[cfg(target_arch = "x86_64")] + with_framebuffer(|fb| fb.setup_x86_64()); } } @@ -127,6 +126,7 @@ unsafe extern "C" fn kmain() -> ! { println!("Could not get date at boot. Will default to 0.") } + #[cfg(target_arch = "x86_64")] run_elf(INIT_ELF_BYTES, false); loop {} @@ -134,6 +134,12 @@ unsafe extern "C" fn kmain() -> ! { #[panic_handler] fn rust_panic(_info: &core::panic::PanicInfo) -> ! { + #[cfg(target_arch = "x86_64")] + { + serial_print("\nKERNEL PANIC:\n"); + serial_print(_info.message().as_str().unwrap()); + serial_print("\n"); + } with_framebuffer(|mut fb| { fb.clear(rgb(180, 0, 0)); diff --git a/kernel/src/mm/address_space.rs b/kernel/src/mm/address_space.rs index 3e0cc35..12bbdc5 100644 --- a/kernel/src/mm/address_space.rs +++ b/kernel/src/mm/address_space.rs @@ -1,3 +1,4 @@ +#[cfg(target_arch = "x86_64")] use x86_64::{ PhysAddr, VirtAddr, registers::control::{Cr3, Cr3Flags}, @@ -6,10 +7,16 @@ use x86_64::{ use crate::arch::arch::FRAME_ALLOCATOR; +#[cfg(target_arch = "x86_64")] pub struct AddressSpace { cr3_frame: PhysFrame, pub mapper: OffsetPageTable<'static>, } + +#[cfg(target_arch = "aarch64")] +pub struct AddressSpace {} + +#[cfg(target_arch = "x86_64")] impl AddressSpace { pub fn new() -> Option { let mut frame_allocator = FRAME_ALLOCATOR.lock(); @@ -58,6 +65,7 @@ impl AddressSpace { } } +#[cfg(target_arch = "x86_64")] pub unsafe fn physical_to_virt_pointer(phys_addr: PhysAddr, hhdm_offset: u64) -> *mut u64 { (hhdm_offset + phys_addr.as_u64()) as *mut u64 } diff --git a/kernel/src/mm/heap.rs b/kernel/src/mm/heap.rs new file mode 100644 index 0000000..7b114ea --- /dev/null +++ b/kernel/src/mm/heap.rs @@ -0,0 +1,140 @@ +use core::{ + alloc::{GlobalAlloc, Layout}, + ptr::null_mut, +}; + +use crate::util::{Locked, align_up}; + +pub struct LinkedNode { + pub size: usize, + pub next: Option<&'static mut LinkedNode>, +} + +impl LinkedNode { + pub const fn new(size: usize) -> LinkedNode { + LinkedNode { size, next: None } + } + + pub fn start_addr(&self) -> usize { + self as *const Self as usize + } + + pub fn end_addr(&self) -> usize { + self.start_addr() + self.size + } +} + +pub struct LinkedListAllocator { + head: LinkedNode, +} + +impl LinkedListAllocator { + pub const fn new() -> LinkedListAllocator { + Self { + head: LinkedNode::new(0), + } + } + + fn size_align(layout: Layout) -> (usize, usize) { + let layout = layout + .align_to(16) + .expect("Align to LinkedNode failed") + .pad_to_align(); + + let size = layout.size().max(core::mem::size_of::()); // either take layout's size or atleast the size of a single linked node. + + (size, layout.align()) + } + + pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) { + unsafe { + self.add_free_memory_region(heap_start, heap_size); + } + } + + unsafe fn add_free_memory_region(&mut self, start: usize, size: usize) { + assert_eq!(align_up(start as u64, 16), start as u64); // Check if we are up at least 1 LinkedNode size + assert!(size >= core::mem::size_of::()); // check if we have enough space for a LinkedNode + + let mut linked_node = LinkedNode::new(size); + linked_node.next = self.head.next.take(); + + let linked_node_ptr = start as *mut LinkedNode; // Treat the start memory region as a LinkedNode type + unsafe { + linked_node_ptr.write(linked_node); // write the data, very risky + self.head.next = Some(&mut *linked_node_ptr); + } + } + + fn find_region( + &mut self, + size: usize, + align: usize, + ) -> Option<(&'static mut LinkedNode, usize)> { + let mut current = &mut self.head; + + while let Some(ref mut region) = current.next { + if let Ok(alloc_start) = Self::alloc_from_region(®ion, size, align) { + let next = region.next.take(); + let ret = Some((current.next.take().unwrap(), alloc_start)); + current.next = next; + + return ret; + } else { + current = current.next.as_mut().unwrap(); + } + } + + None + } + + fn alloc_from_region(region: &LinkedNode, size: usize, align: usize) -> Result { + let alloc_start = align_up(region.start_addr() as u64, align as u64) as usize; + let alloc_end = alloc_start.checked_add(size).ok_or(())?; // check for overflows + + if alloc_end > region.end_addr() { + return Err(()); + } + + let excess_size = region.end_addr() - alloc_end; + if excess_size > 0 && excess_size < core::mem::size_of::() { + // if the remaining space is not enough for another LinkedNode, skip this region. + return Err(()); + } + + Ok(alloc_start) + } +} + +unsafe impl GlobalAlloc for Locked { + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + let (size, align) = LinkedListAllocator::size_align(_layout); + let mut allocator = self.lock(); + + if let Some((region, alloc_start)) = allocator.find_region(size, align) { + let alloc_end = alloc_start.checked_add(size).expect("overflow"); + + let excess_size = region.end_addr() - alloc_end; + + if excess_size > 0 { + unsafe { + allocator.add_free_memory_region(alloc_end, excess_size); + } + } + + drop(allocator); + + alloc_start as *mut u8 + } else { + null_mut() + } + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + let (size, _) = LinkedListAllocator::size_align(_layout); + + unsafe { + self.lock().add_free_memory_region(_ptr as usize, size); + } + } +} diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 38c0c0d..7c49e7e 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -1,2 +1,3 @@ pub mod address_space; +pub mod heap; pub mod usercopy; diff --git a/kernel/src/mm/usercopy.rs b/kernel/src/mm/usercopy.rs index 21df0f0..fa6f510 100644 --- a/kernel/src/mm/usercopy.rs +++ b/kernel/src/mm/usercopy.rs @@ -2,11 +2,14 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; + +#[cfg(target_arch = "x86_64")] use x86_64::{ VirtAddr, structures::paging::{OffsetPageTable, PageTableFlags, Translate, mapper::TranslateResult}, }; +#[cfg(target_arch = "x86_64")] pub fn copy_to_user( mapper: &mut OffsetPageTable, buf: *mut u8, @@ -42,6 +45,7 @@ pub fn copy_to_user( Ok(()) } +#[cfg(target_arch = "x86_64")] pub fn copy_from_user( mapper: &mut OffsetPageTable, buf: *mut u8, @@ -85,6 +89,7 @@ pub fn copy_from_user( Ok(()) } +#[cfg(target_arch = "x86_64")] pub fn copy_cstr_from_user( mapper: &mut OffsetPageTable, user_ptr: *const u8, diff --git a/kernel/src/task/scheduler.rs b/kernel/src/task/scheduler.rs index 9ebbdc3..98c1a12 100644 --- a/kernel/src/task/scheduler.rs +++ b/kernel/src/task/scheduler.rs @@ -1,10 +1,9 @@ use core::sync::atomic::{AtomicU64, Ordering}; use alloc::{collections::btree_map::BTreeMap, vec::Vec}; -use x86_64::instructions::interrupts::without_interrupts; use crate::{ - arch::arch::enter_usermode, + arch::arch::{enter_usermode, safe_lock}, task::{ context::UserContext, process::{Process, ProcessState}, @@ -43,7 +42,7 @@ impl Scheduler { impl Locked { pub fn spawn_process(&self, entry_point: u64, stack_top: u64, heap_base: u64) -> Option { - let mut guard = without_interrupts(|| self.lock()); + let mut guard = safe_lock(|| self.lock()); let pid = guard.next_pid; guard.next_pid += 1; let process = Process::new(pid, entry_point, stack_top, heap_base, heap_base); @@ -54,7 +53,7 @@ impl Locked { pub fn next_task(&self) -> u64 { if let Some(previous_pid) = current_pid() { - let mut guard = without_interrupts(|| self.lock()); + let mut guard = safe_lock(|| self.lock()); if let Some(process) = guard.processes.get_mut(&previous_pid) { if matches!(process.state, ProcessState::Running) { @@ -87,9 +86,10 @@ impl Locked { }; } + #[cfg(target_arch = "x86_64")] pub fn switch_to(&self, pid: u64, should_swapgs: bool) { let (ctx_opt, entry, stack_top) = { - let mut guard = without_interrupts(|| self.lock()); + let mut guard = safe_lock(|| self.lock()); if let Some(previous_pid) = current_pid() { if let Some(old_process) = guard.processes.get_mut(&previous_pid) { @@ -128,7 +128,7 @@ impl Locked { where F: FnOnce(&mut Process) -> R, { - let mut guard = without_interrupts(|| self.lock()); + let mut guard = safe_lock(|| self.lock()); let process = guard.processes.get_mut(&index)?; Some(f(process)) } @@ -136,6 +136,7 @@ impl Locked { pub static SCHEDULER: Locked = Locked::new(Scheduler::new()); +#[cfg(target_arch = "x86_64")] #[unsafe(naked)] #[unsafe(no_mangle)] unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) { diff --git a/kernel/src/util.rs b/kernel/src/util.rs index 5a6ab15..9d3394b 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -5,6 +5,20 @@ pub struct Locked { inner: Mutex, } +#[cfg(target_arch = "x86_64")] +pub fn serial_print_byte(b: u8) { + unsafe { + core::arch::asm!("out dx, al", in("dx") 0x3F8u16, in("al") b); + } +} + +#[cfg(target_arch = "x86_64")] +pub fn serial_print(s: &str) { + for &b in s.as_bytes() { + serial_print_byte(b); + } +} + impl Locked { pub const fn new(inner: A) -> Self { Locked { @@ -49,9 +63,3 @@ pub const fn align_up(addr: u64, align: u64) -> u64 { } } } - -pub fn serial_print(s: &str) { - for byte in s.bytes() { - unsafe { core::arch::asm!("out dx, al", in("dx") 0x3F8u16, in("al") byte) } - } -}