From 812d4cf6d49c458158a40efec0b48d7d9b2ecff1 Mon Sep 17 00:00:00 2001 From: csd4ni3l <96988024+csd4ni3l@users.noreply.github.com> Date: Sat, 16 May 2026 00:30:01 +0200 Subject: [PATCH] Patched everything for aarch64, aside from scheduler, add more linker points to aarch64 ld, add aarch64 heap, init, page tables and usermode, make hhdm_offset a global atomic, aarch64 uses semihosting for output, add generic PageTable type, add a function that creates and maps pages, use allow to remove warnings, add a bufwriter so kernel panic always works --- .gitignore | 1 + GNUmakefile | 1 + kernel/linker-aarch64.ld | 28 +-- kernel/src/arch/aarch64/heap.rs | 23 +- kernel/src/arch/aarch64/init.rs | 23 +- kernel/src/arch/aarch64/interrupts.rs | 1 + kernel/src/arch/aarch64/keyboard.rs | 1 + kernel/src/arch/aarch64/mod.rs | 4 + kernel/src/arch/aarch64/mouse.rs | 1 + kernel/src/arch/aarch64/paging.rs | 278 +++++++++++++++++++++- kernel/src/arch/aarch64/syscall.rs | 1 + kernel/src/arch/aarch64/usermode.rs | 15 ++ kernel/src/arch/arch.rs | 91 ++++--- kernel/src/arch/syscall.rs | 135 +++++------ kernel/src/arch/x86_64/elf.rs | 62 ----- kernel/src/arch/x86_64/heap.rs | 41 +--- kernel/src/arch/x86_64/init.rs | 31 +-- kernel/src/arch/x86_64/mod.rs | 1 - kernel/src/arch/x86_64/paging.rs | 39 ++- kernel/src/arch/x86_64/usermode.rs | 6 +- kernel/src/driver/elf/header.rs | 7 + kernel/src/driver/elf/loader.rs | 66 ++++- kernel/src/driver/elf/program.rs | 124 +++++----- kernel/src/driver/fs/vfs.rs | 1 + kernel/src/driver/graphics/framebuffer.rs | 45 +++- kernel/src/main.rs | 86 ++++++- kernel/src/mm/address_space.rs | 68 ++++-- kernel/src/mm/usercopy.rs | 103 +++++--- kernel/src/task/context.rs | 6 + kernel/src/task/scheduler.rs | 11 +- kernel/src/util.rs | 14 -- user/libxunil | 2 +- 32 files changed, 911 insertions(+), 405 deletions(-) create mode 100644 kernel/src/arch/aarch64/interrupts.rs create mode 100644 kernel/src/arch/aarch64/keyboard.rs create mode 100644 kernel/src/arch/aarch64/mouse.rs create mode 100644 kernel/src/arch/aarch64/syscall.rs create mode 100644 kernel/src/arch/aarch64/usermode.rs delete mode 100644 kernel/src/arch/x86_64/elf.rs diff --git a/.gitignore b/.gitignore index 58d3fcf..13e6c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /limine +/.zed /edk2-ovmf *.iso *.hdd diff --git a/GNUmakefile b/GNUmakefile index 673cbcf..96ba9a2 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -54,6 +54,7 @@ run-aarch64: edk2-ovmf $(IMAGE_NAME).iso -serial stdio \ -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -cdrom $(IMAGE_NAME).iso \ + -semihosting-config enable=on,target=native \ $(QEMUFLAGS) .PHONY: run-hdd-aarch64 diff --git a/kernel/linker-aarch64.ld b/kernel/linker-aarch64.ld index 2c38122..e40ab19 100644 --- a/kernel/linker-aarch64.ld +++ b/kernel/linker-aarch64.ld @@ -22,38 +22,30 @@ SECTIONS /* that is the beginning of the region. */ . = 0xffffffff80000000; - .text : { - *(.text .text.*) - } :text - - /* Move to the next memory page for .rodata */ + __kernel_start = .; + __text_start = .; + .text : { *(.text .text.*) } :text . = ALIGN(CONSTANT(MAXPAGESIZE)); + __text_end = .; - .rodata : { - *(.rodata .rodata.*) - } :rodata - - /* Move to the next memory page for .data */ + __rodata_start = .; + .rodata : { *(.rodata .rodata.*) } :rodata . = ALIGN(CONSTANT(MAXPAGESIZE)); + __rodata_end = .; + __data_start = .; .data : { *(.data .data.*) - - /* Place the sections that contain the Limine requests as part of the .data */ - /* output section. */ KEEP(*(.requests_start_marker)) KEEP(*(.requests)) KEEP(*(.requests_end_marker)) } :data - - /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ - /* unnecessary zeros will be written to the binary. */ - /* If you need, for example, .init_array and .fini_array, those should be placed */ - /* above this. */ .bss : { *(.bss .bss.*) *(COMMON) } :data + __data_end = .; + __kernel_end = .; /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ /DISCARD/ : { diff --git a/kernel/src/arch/aarch64/heap.rs b/kernel/src/arch/aarch64/heap.rs index 9dea8dd..30a5634 100644 --- a/kernel/src/arch/aarch64/heap.rs +++ b/kernel/src/arch/aarch64/heap.rs @@ -1,3 +1,24 @@ -use crate::{mm::heap::LinkedListAllocator, util::Locked}; +use crate::{ + arch::aarch64::paging::{AArchPageTable, alloc_frame, kernel_data_flags}, + mm::heap::LinkedListAllocator, + util::Locked, +}; #[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 fn init_heap(mapper: &mut AArchPageTable) { + let pages = HEAP_SIZE / 4096; + + for i in 0..pages { + let phys = alloc_frame().expect("frame allocator out of frames"); + let virt = HEAP_START as u64 + i as u64 * 4096; + mapper.map_page(virt, phys, kernel_data_flags()); + } + + unsafe { + ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE); + } +} diff --git a/kernel/src/arch/aarch64/init.rs b/kernel/src/arch/aarch64/init.rs index 1cd0f1e..c58b0cf 100644 --- a/kernel/src/arch/aarch64/init.rs +++ b/kernel/src/arch/aarch64/init.rs @@ -1,2 +1,21 @@ -use limine::response::{HhdmResponse, MemoryMapResponse}; -pub fn init_aarch64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {} +use crate::arch::aarch64::{ + heap::init_heap, + paging::{AArchPageTable, initialize_paging_aarch64}, +}; +use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse}; + +pub fn init_aarch64<'a>( + hhdm_response: &HhdmResponse, + memory_map_response: &'a MemoryMapResponse, + executable_address_response: &ExecutableAddressResponse, +) -> AArchPageTable { + let mut mapper = initialize_paging_aarch64( + hhdm_response, + memory_map_response, + executable_address_response, + ); + + init_heap(&mut mapper); + + return mapper; +} diff --git a/kernel/src/arch/aarch64/interrupts.rs b/kernel/src/arch/aarch64/interrupts.rs new file mode 100644 index 0000000..54e1ac6 --- /dev/null +++ b/kernel/src/arch/aarch64/interrupts.rs @@ -0,0 +1 @@ +// TODO: add interrupts diff --git a/kernel/src/arch/aarch64/keyboard.rs b/kernel/src/arch/aarch64/keyboard.rs new file mode 100644 index 0000000..9f6d18f --- /dev/null +++ b/kernel/src/arch/aarch64/keyboard.rs @@ -0,0 +1 @@ +// TODO: add keyboard logic diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index c79cb30..cec215e 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -1,3 +1,7 @@ pub mod heap; pub mod init; +pub mod interrupts; +pub mod mouse; pub mod paging; +pub mod syscall; +pub mod usermode; diff --git a/kernel/src/arch/aarch64/mouse.rs b/kernel/src/arch/aarch64/mouse.rs new file mode 100644 index 0000000..0703d0a --- /dev/null +++ b/kernel/src/arch/aarch64/mouse.rs @@ -0,0 +1 @@ +// TODO: add mouse logic diff --git a/kernel/src/arch/aarch64/paging.rs b/kernel/src/arch/aarch64/paging.rs index e9eb83c..6b7945b 100644 --- a/kernel/src/arch/aarch64/paging.rs +++ b/kernel/src/arch/aarch64/paging.rs @@ -1,5 +1,281 @@ -use crate::arch::arch::XunilFrameAllocator; +use crate::arch::arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock}; +use limine::{ + memory_map::EntryType, + response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse}, +}; use spin::Mutex; pub static FRAME_ALLOCATOR_AARCH64: Mutex = Mutex::new(XunilFrameAllocator::new()); + +// Constants +const VALID: u64 = 1 << 0; +const TABLE: u64 = 1 << 1; +const PAGE: u64 = 1 << 1; +const AF: u64 = 1 << 10; +const SH_INNER: u64 = 0b11 << 8; + +const ATTR_NORMAL: u64 = 0 << 2; +const ATTR_DEVICE: u64 = 1 << 2; + +// AP bits +const AP_RW_EL1: u64 = 0b00 << 6; // kernel RW +const AP_RO_EL1: u64 = 0b10 << 6; // kernel RO +const AP_RW_EL0: u64 = 0b01 << 6; // kernel RW, user RW +const AP_RO_EL0: u64 = 0b11 << 6; // kernel RO, user RO + +pub const UXN: u64 = 1 << 54; // unprivileged execute never +const PXN: u64 = 1 << 53; // privileged execute never + +pub fn kernel_data_flags() -> u64 { + VALID | PAGE | AF | SH_INNER | AP_RW_EL1 | UXN | ATTR_NORMAL +} + +pub fn kernel_code_flags() -> u64 { + VALID | PAGE | AF | SH_INNER | AP_RO_EL1 | ATTR_NORMAL // no UXN +} + +pub fn user_data_flags() -> u64 { + VALID | PAGE | AF | SH_INNER | AP_RW_EL0 | UXN | PXN | ATTR_NORMAL +} + +pub fn user_code_flags() -> u64 { + VALID | PAGE | AF | SH_INNER | AP_RO_EL0 | ATTR_NORMAL // no UXN +} + +pub fn device_flags() -> u64 { + VALID | PAGE | AF | AP_RW_EL1 | UXN | PXN | ATTR_DEVICE + // no SH bits for device memory +} + +fn phys_to_virt(phys: u64) -> *mut u64 { + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); + (phys + hhdm_offset) as *mut u64 +} + +pub fn tlb_flush() { + unsafe { + core::arch::asm!( + "tlbi vmalle1is", // invalidate TLB + "dsb ish", // wait for tlb flush + "isb", + ) + } +} + +pub fn set_page_table(root_phys: u64) { + unsafe { + core::arch::asm!( + "msr ttbr1_el1, {root}", // set to new page table + "isb", + root = in(reg) root_phys + ) + } +} + +// translation control register: handles addresses +fn setup_tcr() { + unsafe { + let tcr: u64 = (16 << 0) | // T0SZ: 48-bit VA for TTBR0 (64-48=16) + (16 << 16) | // T1SZ: 48-bit VA for TTBR1 + (0b00 << 14)| // TG0: 4K granule + (0b10 << 30)| // TG1: 4K granule + (0b11 << 12)| // SH0: inner shareable + (0b11 << 28)| // SH1: inner shareable + (0b01 << 10)| // ORGN0: normal WB RAWA + (0b01 << 26)| // ORGN1 + (0b01 << 8) | // IRGN0 + (0b01 << 24); // IRGN1 + core::arch::asm!("msr tcr_el1, {0}", in(reg) tcr); + } +} + +pub fn initialize_paging_aarch64<'a>( + hhdm_response: &HhdmResponse, + memory_map_response: &'a MemoryMapResponse, + executable_address_response: &ExecutableAddressResponse, +) -> AArchPageTable { + let mut frame_allocator = FRAME_ALLOCATOR_AARCH64.lock(); + frame_allocator.initialize(memory_map_response.entries()); + drop(frame_allocator); + + let page_table = AArchPageTable::new(); + + unsafe extern "C" { + static __text_end: u8; + static __kernel_start: u8; + static __kernel_end: u8; + } + + let k_phys_base = executable_address_response.physical_base(); + let k_virt_base = executable_address_response.virtual_base(); + + let text_end = unsafe { &__text_end as *const u8 as u64 }; + let k_start_virt = unsafe { (&__kernel_start as *const u8) as u64 }; + let k_end_virt = unsafe { (&__kernel_end as *const u8) as u64 }; + + let k_phys = k_phys_base + (k_start_virt - k_virt_base); + + // map the kernel so we dont crash lol + page_table.map_range( + k_start_virt, + k_phys, + text_end - k_start_virt, + kernel_code_flags(), + ); + + page_table.map_range( + text_end, + k_phys + (text_end - k_start_virt), + k_end_virt - text_end, + kernel_data_flags(), + ); + + // i need to map the entire memory range + for entry in memory_map_response.entries() { + if entry.entry_type == EntryType::BAD_MEMORY || entry.entry_type == EntryType::RESERVED { + continue; + } + + let flags = if entry.entry_type == EntryType::FRAMEBUFFER { + device_flags() + } else { + kernel_data_flags() + }; + + page_table.map_range( + entry.base + hhdm_response.offset(), + entry.base, + entry.length, + flags, + ); + } + + page_table.map_page(0xFFFF_0000_0900_0000, 0x0900_0000, device_flags()); // the UART + + setup_tcr(); + set_page_table(page_table.root_phys); + tlb_flush(); + + return page_table; +} + +pub struct AArchPageTable { + pub root_phys: u64, +} + +pub fn alloc_frame() -> Option { + let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR_AARCH64.lock()); + let frame = frame_allocator.allocate_frame(); + drop(frame_allocator); + return frame; +} + +impl AArchPageTable { + pub fn new() -> AArchPageTable { + let mut frame_allocator = safe_lock(|| FRAME_ALLOCATOR_AARCH64.lock()); + let root_phys = frame_allocator + .allocate_frame() + .expect("Could not allocate frame for page table"); + + unsafe { + core::ptr::write_bytes(phys_to_virt(root_phys), 0, 512); + } + + AArchPageTable { root_phys } + } + + pub fn table_ptr(&self, table_phys: u64, index: usize) -> *mut u64 { + let table_virt = phys_to_virt(table_phys); + + unsafe { table_virt.add(index) } + } + + pub fn get_or_create_table(&self, parent_phys: u64, index: usize) -> u64 { + let entry_ptr = self.table_ptr(parent_phys, index); + let entry = unsafe { entry_ptr.read_volatile() }; + + if entry & VALID != 0 { + return entry & 0x0000_FFFF_FFFF_F000; + } else { + let child = alloc_frame().expect("Could not allocate frame when creating page table"); + unsafe { + core::ptr::write_bytes(phys_to_virt(child), 0, 512); + entry_ptr.write_volatile(child | VALID | TABLE); + } + return child; + } + } + + pub fn map_page(&self, virt: u64, phys: u64, flags: u64) { + let l0 = ((virt >> 39) & 0x1FF) as usize; + let l1 = ((virt >> 30) & 0x1FF) as usize; + let l2 = ((virt >> 21) & 0x1FF) as usize; + let l3 = ((virt >> 12) & 0x1FF) as usize; + + let l1_phys = self.get_or_create_table(self.root_phys, l0); + let l2_phys = self.get_or_create_table(l1_phys, l1); + let l3_phys = self.get_or_create_table(l2_phys, l2); + + let entry_ptr = self.table_ptr(l3_phys, l3); + + unsafe { + entry_ptr.write_volatile(phys | flags); + } + } + + pub fn map_range(&self, virt: u64, phys: u64, size: u64, flags: u64) { + let pages = (size + 4095) / 4096; + + for i in 0..pages { + self.map_page(virt + i * 4096, phys + i * 4096, flags); + } + } +} + +impl XunilFrameAllocator { + pub fn allocate_frame(&mut self) -> Option { + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); + while self.region_index < self.usable_region_count { + let region = self.usable_regions[self.region_index]; + let frame_count = region.length / 4096; + + 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 + hhdm_offset) as *mut u8, 0, 4096); + } + + return Some(addr); + } + + self.region_index += 1; + self.region_offset = 0; + } + + None + } +} + +pub fn create_and_map_multiple_pages( + mapper: &mut AArchPageTable, + page_count: u64, + base: u64, + flags: u64, +) { + let mut frame_allocator = FRAME_ALLOCATOR_AARCH64.lock(); + + for i in 0..page_count { + let frame = frame_allocator.allocate_frame().unwrap(); + + let virt = base + i as u64 * 4096; + + mapper.map_page(virt, frame, flags); + } + + tlb_flush(); + + drop(frame_allocator); +} diff --git a/kernel/src/arch/aarch64/syscall.rs b/kernel/src/arch/aarch64/syscall.rs new file mode 100644 index 0000000..1325e4c --- /dev/null +++ b/kernel/src/arch/aarch64/syscall.rs @@ -0,0 +1 @@ +// TODO: add syscalls diff --git a/kernel/src/arch/aarch64/usermode.rs b/kernel/src/arch/aarch64/usermode.rs new file mode 100644 index 0000000..5b3cee2 --- /dev/null +++ b/kernel/src/arch/aarch64/usermode.rs @@ -0,0 +1,15 @@ +#[allow(unused_variables)] +pub fn enter_usermode_aarch64(entry: u64, stack_ptr: u64, should_swapgs: bool) -> ! { + unsafe { + core::arch::asm!( + "msr sp_el0, {sp}", + "msr elr_el1, {entry}", + "msr spsr_el1, xzr", + "isb", + "eret", + sp = in(reg) stack_ptr, + entry = in(reg) entry, + options(noreturn) + ) + }; +} diff --git a/kernel/src/arch/arch.rs b/kernel/src/arch/arch.rs index 81edc73..ef6b966 100644 --- a/kernel/src/arch/arch.rs +++ b/kernel/src/arch/arch.rs @@ -1,16 +1,35 @@ +#![allow(dead_code, unused_imports)] #[cfg(target_arch = "x86_64")] pub use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64 as FRAME_ALLOCATOR; +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::{init::init_x86_64, usermode::enter_usermode_x86_64}; +#[cfg(target_arch = "aarch64")] +use limine::response::ExecutableAddressResponse; +#[cfg(target_arch = "x86_64")] +use x86_64::{ + instructions::interrupts::without_interrupts, + structures::paging::{FrameAllocator, OffsetPageTable, PhysFrame, Size4KiB}, +}; #[cfg(target_arch = "aarch64")] pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR; +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::{ + init::init_aarch64, paging::AArchPageTable, usermode::enter_usermode_aarch64, +}; use crate::{driver::timer::TIMER, util::align_up}; -use core::arch::asm; +use core::{arch::asm, sync::atomic::AtomicU64}; use limine::{ memory_map::{Entry, EntryType}, response::{HhdmResponse, MemoryMapResponse}, }; +#[cfg(target_arch = "aarch64")] +const UART: *mut u8 = 0x0900_0000 as *mut u8; + +pub static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0); + #[derive(Clone, Copy)] #[allow(dead_code)] pub struct UsableRegion { @@ -40,7 +59,7 @@ impl XunilFrameAllocator { } } - pub fn initialize(&mut self, hhdm_offset: u64, memory_map: &[&Entry]) { + pub fn initialize(&mut self, memory_map: &[&Entry]) { let mut regions = [EMPTY_REGION; 1024]; let mut count = 0usize; @@ -63,7 +82,7 @@ impl XunilFrameAllocator { } } - self.hhdm_offset = hhdm_offset; + self.hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); self.usable_regions = regions; self.usable_region_count = count; self.region_index = 0; @@ -71,16 +90,6 @@ impl XunilFrameAllocator { } } -#[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::{ - elf::run_elf_x86_64, init::init_x86_64, usermode::enter_usermode_x86_64, -}; -#[cfg(target_arch = "x86_64")] -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>( hhdm_response: &HhdmResponse, @@ -90,28 +99,26 @@ pub fn init<'a>( } #[cfg(target_arch = "aarch64")] -pub fn init<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) { - return init_aarch64(hhdm_response, memory_map_response); +pub fn init<'a>( + hhdm_response: &HhdmResponse, + memory_map_response: &'a MemoryMapResponse, + executable_address_response: &ExecutableAddressResponse, +) -> AArchPageTable { + return init_aarch64( + hhdm_response, + memory_map_response, + executable_address_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); +pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) { + enter_usermode_x86_64(entry, stack_ptr, 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); -} - -#[cfg(target_arch = "aarch64")] -pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) { - unimplemented!() +pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) { + enter_usermode_aarch64(entry, stack_ptr, should_swapgs); } pub fn safe_lock R>(f: F) -> R { @@ -121,6 +128,32 @@ pub fn safe_lock R>(f: F) -> R { return f(); } +#[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 = "aarch64")] +pub fn serial_print_byte(b: u8) { + unsafe { + let buf = [b]; + core::arch::asm!( + "hlt #0xF000", + in("x0") 0x03u64, // SYS_WRITEC + in("x1") buf.as_ptr(), + options(nostack) + ); + } +} + +pub fn serial_print(s: &str) { + for &b in s.as_bytes() { + serial_print_byte(b); + } +} + pub fn idle() { unsafe { #[cfg(target_arch = "x86_64")] diff --git a/kernel/src/arch/syscall.rs b/kernel/src/arch/syscall.rs index 7039c7c..1195ae1 100644 --- a/kernel/src/arch/syscall.rs +++ b/kernel/src/arch/syscall.rs @@ -1,16 +1,22 @@ -#![allow(dead_code)] - +#![allow(dead_code, unused_imports)] +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::paging::create_and_map_multiple_pages; use alloc::vec; #[cfg(target_arch = "x86_64")] use x86_64::{ PhysAddr, VirtAddr, instructions::interrupts, - structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB}, + structures::paging::{ + FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags, PhysFrame, Size4KiB, + }, }; +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::paging::AArchPageTable; use crate::{ - arch::arch::{FRAME_ALLOCATOR, run_elf, sleep}, + arch::arch::{FRAME_ALLOCATOR, sleep}, driver::{ + elf::loader::run_elf, fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read}, graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer}, keyboard::{KeyboardEvent, process_scancodes}, @@ -24,7 +30,6 @@ 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}, @@ -56,7 +61,12 @@ const SLEEP: usize = 909090; // zzz haha pub const MAP_FRAMEBUFFER: usize = 5555; pub const FRAMEBUFFER_SWAP: usize = 6666; +#[cfg(target_arch = "aarch64")] +type PageTable = AArchPageTable; + #[cfg(target_arch = "x86_64")] +type PageTable<'a> = OffsetPageTable<'a>; + fn map_framebuffer() -> isize { let pid = current_pid().unwrap_or(0); if pid == 0 { @@ -76,18 +86,20 @@ fn map_framebuffer() -> isize { let pixel_map_end = align_up(buf_phys + buf_size, 4096); drop(framebuffer); - let mut frame_allocator = FRAME_ALLOCATOR.lock(); - SCHEDULER .with_process(pid, |process| { let address_space = match process.address_space.as_mut() { Some(a) => a, None => return -1, }; - + #[allow(dead_code, unused_mut, unused_variables)] + let mut map_page = |virt: u64, phys: u64| {}; + #[cfg(target_arch = "x86_64")] let mut map_page = |virt: u64, phys: u64| unsafe { let frame = PhysFrame::::containing_address(PhysAddr::new(phys)); let page = Page::::containing_address(VirtAddr::new(virt)); + let mut frame_allocator = FRAME_ALLOCATOR.lock(); + address_space .mapper .map_to( @@ -101,6 +113,14 @@ fn map_framebuffer() -> isize { ) .unwrap() .flush(); + + drop(frame_allocator); + }; + #[cfg(target_arch = "aarch64")] + let map_page = |virt: u64, phys: u64| { + use crate::arch::aarch64::paging::user_data_flags; + + address_space.mapper.map_page(virt, phys, user_data_flags()); }; map_page(USER_FB_BASE, struct_phys); @@ -114,12 +134,6 @@ 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 { @@ -155,12 +169,6 @@ 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 { @@ -179,16 +187,10 @@ 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() { @@ -223,12 +225,6 @@ 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); @@ -238,8 +234,6 @@ pub unsafe fn sbrk(increment: isize) -> isize { 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); @@ -262,40 +256,35 @@ pub unsafe fn sbrk(increment: isize) -> isize { if new > old { let map_start = align_up(old, 4096); - let map_end = align_up(new, 4096); + let page_count = (align_up(new, 4096) - map_start) / 4096; + if let Some(address_space) = process.address_space.as_mut() { + #[cfg(target_arch = "x86_64")] + create_and_map_multiple_pages( + &mut address_space.mapper, + page_count, + map_start, + PageTableFlags::PRESENT + | PageTableFlags::WRITABLE + | PageTableFlags::USER_ACCESSIBLE + | PageTableFlags::NO_EXECUTE, + ); + #[cfg(target_arch = "aarch64")] + { + use crate::arch::aarch64::paging::{ + create_and_map_multiple_pages, user_data_flags, + }; - for addr in (map_start..map_end).step_by(4096) { - if let Some(frame) = frame_allocator.allocate_frame() { - // TODO: do not use x86_64 only - let virt_addr = VirtAddr::new(addr); - let page = Page::::containing_address(virt_addr); - if let Some(address_space) = process.address_space.as_mut() { - unsafe { - address_space - .mapper - .map_to( - page, - frame, - PageTableFlags::PRESENT - | PageTableFlags::WRITABLE - | PageTableFlags::USER_ACCESSIBLE - | PageTableFlags::NO_EXECUTE, - &mut *frame_allocator, - ) - .unwrap() - .flush(); - - core::ptr::write_bytes(virt_addr.as_mut_ptr::(), 0, 4096); - } - } else { - return -1; - } - } else { - return -1; + create_and_map_multiple_pages( + &mut address_space.mapper, + page_count, + map_start, + user_data_flags(), + ); } + } else { + return -1; } } - drop(frame_allocator); process.heap_end = new; @@ -304,12 +293,6 @@ 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 { @@ -374,11 +357,6 @@ 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); @@ -395,7 +373,6 @@ 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 { @@ -427,11 +404,7 @@ pub fn exit() -> isize { crate::arch::arch::infinite_idle(); } -#[cfg(target_arch = "aarch64")] -pub fn exit() -> isize { - 0 -} - +#[allow(unused_variables)] #[unsafe(no_mangle)] pub unsafe extern "C" fn syscall_dispatch( num: usize, diff --git a/kernel/src/arch/x86_64/elf.rs b/kernel/src/arch/x86_64/elf.rs deleted file mode 100644 index 6d157b0..0000000 --- a/kernel/src/arch/x86_64/elf.rs +++ /dev/null @@ -1,62 +0,0 @@ -use alloc::vec::Vec; -use x86_64::{ - VirtAddr, - structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB}, -}; - -use crate::{ - arch::arch::FRAME_ALLOCATOR, driver::elf::loader::load_file, mm::address_space::AddressSpace, - println, task::scheduler::SCHEDULER, -}; - -pub fn run_elf_x86_64(file_bytes: &[u8], should_swapgs: bool) { - let stack_base: u64 = 0x0000_7fff_0000_0000; - let page_count = 4096; // 16 mib - let page_size = 0x1000u64; - let stack_top = stack_base + (page_count as u64 * page_size); - - if let Some(mut address_space) = AddressSpace::new() { - address_space.use_address_space(); - - let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes); - - println!("Entry point: {:?}", entry_point); - - let process_pid = SCHEDULER - .spawn_process(entry_point as u64, stack_top, heap_base) - .unwrap(); - - let mut frame_allocator = FRAME_ALLOCATOR.lock(); - - for i in 0..page_count { - let frame = frame_allocator.allocate_frame().unwrap(); - - let virt_addr = VirtAddr::new(stack_base + i as u64 * page_size); - let page = Page::::containing_address(virt_addr); - - unsafe { - address_space - .mapper - .map_to( - page, - frame, - PageTableFlags::PRESENT - | PageTableFlags::WRITABLE - | PageTableFlags::USER_ACCESSIBLE, - &mut *frame_allocator, - ) - .unwrap() - .flush(); - } - } - drop(frame_allocator); - - SCHEDULER.with_process(process_pid, |process| { - process.address_space = Some(address_space) - }); - - SCHEDULER.switch_to(process_pid, should_swapgs); - } else { - return; - }; -} diff --git a/kernel/src/arch/x86_64/heap.rs b/kernel/src/arch/x86_64/heap.rs index 4c7db58..733daca 100644 --- a/kernel/src/arch/x86_64/heap.rs +++ b/kernel/src/arch/x86_64/heap.rs @@ -1,11 +1,8 @@ +use crate::arch::x86_64::paging::create_and_map_multiple_pages; +use crate::mm::heap::LinkedListAllocator; use crate::util::Locked; -use crate::{arch::x86_64::paging::FRAME_ALLOCATOR_X86_64, mm::heap::LinkedListAllocator}; -use x86_64::{ - VirtAddr, - structures::paging::{ - FrameAllocator, Mapper, OffsetPageTable, Page, PageTableFlags as Flags, Size4KiB, - mapper::MapToError, - }, +use x86_64::structures::paging::{ + OffsetPageTable, PageTableFlags as Flags, Size4KiB, mapper::MapToError, }; #[global_allocator] @@ -15,30 +12,14 @@ pub const HEAP_START: usize = 0xffffffff90000000; pub const HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MiB pub fn init_heap(mapper: &mut OffsetPageTable) -> Result<(), MapToError> { - let page_range = { - let page_start = VirtAddr::new(HEAP_START as u64); - let page_end = page_start + HEAP_SIZE as u64 - 1u64; - let heap_start_page: Page = Page::containing_address(page_start); - let heap_end_page: Page = Page::containing_address(page_end); - Page::range_inclusive(heap_start_page, heap_end_page) - }; + let page_count = HEAP_SIZE / 4096; - let mut frame_allocator = FRAME_ALLOCATOR_X86_64.lock(); - - for page in page_range { - let frame = frame_allocator - .allocate_frame() - .ok_or(MapToError::::FrameAllocationFailed)?; - let flags = Flags::PRESENT | Flags::WRITABLE; - unsafe { - mapper - .map_to(page, frame, flags, &mut *frame_allocator) - .map_err(|e| e)? - .flush(); - } - } - - drop(frame_allocator); + create_and_map_multiple_pages( + mapper, + page_count as u64, + HEAP_START as u64, + Flags::PRESENT | Flags::WRITABLE, + ); unsafe { ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE); diff --git a/kernel/src/arch/x86_64/init.rs b/kernel/src/arch/x86_64/init.rs index 24c52ba..967ea81 100644 --- a/kernel/src/arch/x86_64/init.rs +++ b/kernel/src/arch/x86_64/init.rs @@ -1,42 +1,35 @@ use crate::{ arch::x86_64::{ gdt::load_gdt_x86_64, + heap::init_heap, interrupts::{PICS, init_idt_x86_64}, mouse::setup_mouse, + paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64}, syscall::init_syscalls, }, driver::mouse::MOUSE, }; + +use x86_64::{ + VirtAddr, + instructions::{interrupts, interrupts::without_interrupts, port::Port}, + registers::control::{Cr0, Cr0Flags, Cr4, Cr4Flags}, + structures::paging::OffsetPageTable, +}; + use limine::response::{HhdmResponse, MemoryMapResponse}; -use x86_64::{ - instructions::interrupts::without_interrupts, - registers::control::{Cr0, Cr0Flags}, -}; -use x86_64::{ - instructions::{interrupts, port::Port}, - registers::control::{Cr4, Cr4Flags}, -}; const TIMER_PRECISION_HZ: u32 = 1000; const PIT_DIVISOR: u16 = (1_193_182_u32 / TIMER_PRECISION_HZ) as u16; -#[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::{ - heap::init_heap, - paging::{FRAME_ALLOCATOR_X86_64, initialize_paging}, -}; -#[cfg(target_arch = "x86_64")] -use x86_64::{VirtAddr, structures::paging::OffsetPageTable}; - -#[cfg(target_arch = "x86_64")] pub fn memory_management_init( hhdm_response: &HhdmResponse, memory_map_response: &MemoryMapResponse, ) -> OffsetPageTable<'static> { let physical_offset = VirtAddr::new(hhdm_response.offset()); - let mapper = unsafe { initialize_paging(physical_offset) }; + let mapper = unsafe { initialize_paging_x86_64(physical_offset) }; let mut frame_allocator = FRAME_ALLOCATOR_X86_64.lock(); - frame_allocator.initialize(hhdm_response.offset(), memory_map_response.entries()); + frame_allocator.initialize(memory_map_response.entries()); drop(frame_allocator); mapper } diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index 79369ba..3848629 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -1,4 +1,3 @@ -pub mod elf; pub mod gdt; pub mod heap; pub mod init; diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs index 2e0a801..18b358d 100644 --- a/kernel/src/arch/x86_64/paging.rs +++ b/kernel/src/arch/x86_64/paging.rs @@ -2,10 +2,13 @@ use spin::mutex::Mutex; use x86_64::{ PhysAddr, VirtAddr, registers::control::Cr3, - structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB}, + structures::paging::{ + FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PageTableFlags, PhysFrame, + Size4KiB, + }, }; -use crate::arch::arch::XunilFrameAllocator; +use crate::arch::arch::{HHDM_OFFSET, XunilFrameAllocator}; unsafe fn active_level_4_table(mem_offset: VirtAddr) -> &'static mut PageTable { let (level_4_table, _) = Cr3::read(); @@ -17,7 +20,9 @@ unsafe fn active_level_4_table(mem_offset: VirtAddr) -> &'static mut PageTable { unsafe { &mut *page_table_ptr } } -pub unsafe fn initialize_paging(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> { +pub unsafe fn initialize_paging_x86_64( + physical_memory_offset: VirtAddr, +) -> OffsetPageTable<'static> { unsafe { let level_4_table = active_level_4_table(physical_memory_offset); OffsetPageTable::new(level_4_table, physical_memory_offset) @@ -34,8 +39,10 @@ unsafe impl FrameAllocator for XunilFrameAllocator { let addr = region.base + (self.region_offset as u64 * 4096); self.region_offset += 1; + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); + unsafe { - core::ptr::write_bytes((addr + self.hhdm_offset) as *mut u8, 0, 4096); + core::ptr::write_bytes((addr + hhdm_offset) as *mut u8, 0, 4096); } return Some(PhysFrame::containing_address(PhysAddr::new(addr))); @@ -49,5 +56,29 @@ unsafe impl FrameAllocator for XunilFrameAllocator { } } +pub fn create_and_map_multiple_pages( + mapper: &mut OffsetPageTable, + page_count: u64, + base: u64, + flags: PageTableFlags, +) { + let mut frame_allocator = FRAME_ALLOCATOR_X86_64.lock(); + + for i in 0..page_count { + let frame = frame_allocator.allocate_frame().unwrap(); + + let virt_addr = VirtAddr::new(base + i as u64 * 4096); + let page = Page::::containing_address(virt_addr); + + unsafe { + mapper + .map_to(page, frame, flags, &mut *frame_allocator) + .unwrap() + .flush(); + } + } + drop(frame_allocator); +} + pub static FRAME_ALLOCATOR_X86_64: Mutex = Mutex::new(XunilFrameAllocator::new()); diff --git a/kernel/src/arch/x86_64/usermode.rs b/kernel/src/arch/x86_64/usermode.rs index 80386b3..4b4f2bc 100644 --- a/kernel/src/arch/x86_64/usermode.rs +++ b/kernel/src/arch/x86_64/usermode.rs @@ -10,7 +10,7 @@ fn with_rpl3(ss: SegmentSelector) -> u64 { } // entry point and stack -pub fn enter_usermode_x86_64(user_rip: u64, user_rsp: u64, should_swapgs: bool) -> ! { +pub fn enter_usermode_x86_64(entry: u64, stack_ptr: u64, should_swapgs: bool) -> ! { let user_cs = with_rpl3(user_code_selector()); let user_ss = with_rpl3(user_data_selector()); @@ -35,10 +35,10 @@ pub fn enter_usermode_x86_64(user_rip: u64, user_rsp: u64, should_swapgs: bool) "iretq", user_ss = in(reg) user_ss, - user_rsp = in(reg) user_rsp, + user_rsp = in(reg) stack_ptr, rflags = in(reg) rflags, user_cs = in(reg) user_cs, - user_rip = in(reg) user_rip, + user_rip = in(reg) entry, options(noreturn) ); } diff --git a/kernel/src/driver/elf/header.rs b/kernel/src/driver/elf/header.rs index 6c12b70..0733d4d 100644 --- a/kernel/src/driver/elf/header.rs +++ b/kernel/src/driver/elf/header.rs @@ -91,6 +91,13 @@ pub const R_X86_64_RELATIVE: u32 = 8; pub const R_X86_64_32: u32 = 10; pub const R_X86_64_32S: u32 = 11; +// aarch64 relocation types +pub const R_AARCH64_NONE: u32 = 0; +pub const R_AARCH64_ABS64: u32 = 257; +pub const R_AARCH64_GLOB_DAT: u32 = 1025; +pub const R_AARCH64_JUMP_SLOT: u32 = 1026; +pub const R_AARCH64_RELATIVE: u32 = 1027; + // Auxiliary vector types pub const AT_PHDR: u64 = 3; pub const AT_PHENT: u64 = 4; diff --git a/kernel/src/driver/elf/loader.rs b/kernel/src/driver/elf/loader.rs index b97ab48..4f30a41 100644 --- a/kernel/src/driver/elf/loader.rs +++ b/kernel/src/driver/elf/loader.rs @@ -1,22 +1,34 @@ use core::ptr::null; #[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::paging::create_and_map_multiple_pages; +#[allow(unused_imports)] use crate::driver::elf::{ header::{ - EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_X86_64, ET_DYN, ET_EXEC, ET_REL, Elf64Ehdr, + EI_CLASS, EI_DATA, EI_VERSION, ELF_MAGIC, EM_AARCH64, EM_X86_64, ET_DYN, ET_EXEC, ET_REL, + Elf64Ehdr, }, program::load_program, }; + +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::paging::{ + AArchPageTable, create_and_map_multiple_pages, user_data_flags, +}; +use crate::{mm::address_space::AddressSpace, println, task::scheduler::SCHEDULER}; #[cfg(target_arch = "x86_64")] -use x86_64::structures::paging::OffsetPageTable; +use x86_64::structures::paging::{OffsetPageTable, PageTableFlags}; + +#[cfg(target_arch = "aarch64")] +type PageTable = AArchPageTable; #[cfg(target_arch = "x86_64")] +type PageTable<'a> = OffsetPageTable<'a>; + 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; @@ -37,8 +49,7 @@ pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool { && (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) { +pub fn load_file(mapper: &mut PageTable, elf_bytes: &[u8]) -> (*const u8, u64) { // elf header size if elf_bytes.len() < 64 { return (null(), 0); @@ -60,3 +71,46 @@ pub fn load_file(mapper: &mut OffsetPageTable, elf_bytes: &[u8]) -> (*const u8, _ => return (null(), 0), }; } + +pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) { + let stack_base: u64 = 0x0000_7fff_0000_0000; + let page_count = 4096; // 16 mib + let page_size = 0x1000u64; + let stack_top = stack_base + (page_count as u64 * page_size); + + if let Some(mut address_space) = AddressSpace::new() { + address_space.use_address_space(); + + let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes); + + println!("Entry point: {:?}", entry_point); + + let process_pid = SCHEDULER + .spawn_process(entry_point as u64, stack_top, heap_base) + .unwrap(); + + #[cfg(target_arch = "aarch64")] + create_and_map_multiple_pages( + &mut address_space.mapper, + page_count, + stack_base, + user_data_flags(), + ); + + #[cfg(target_arch = "x86_64")] + create_and_map_multiple_pages( + &mut address_space.mapper, + page_count, + stack_base, + PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE, + ); + + SCHEDULER.with_process(process_pid, |process| { + process.address_space = Some(address_space) + }); + + SCHEDULER.switch_to(process_pid, should_swapgs); + } else { + return; + }; +} diff --git a/kernel/src/driver/elf/program.rs b/kernel/src/driver/elf/program.rs index 9e3b1e9..d48f36f 100644 --- a/kernel/src/driver/elf/program.rs +++ b/kernel/src/driver/elf/program.rs @@ -1,6 +1,13 @@ use alloc::vec::Vec; use core::ptr::{null, null_mut}; +#[cfg(target_arch = "aarch64")] +#[allow(unused_imports)] +use crate::arch::aarch64::paging::{ + AArchPageTable, UXN, create_and_map_multiple_pages, user_code_flags, +}; + +#[allow(unused_imports)] #[cfg(target_arch = "x86_64")] use x86_64::{ VirtAddr, @@ -9,13 +16,18 @@ use x86_64::{ }, }; +#[allow(unused_imports)] +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::paging::create_and_map_multiple_pages; +#[allow(unused_imports)] use crate::{ arch::arch::FRAME_ALLOCATOR, driver::elf::header::{ DT_JMPREL, DT_NEEDED, DT_NULL, DT_PLTREL, DT_PLTRELSZ, DT_RELA, DT_RELASZ, DT_STRSZ, DT_STRTAB, DT_SYMTAB, Elf64Dyn, Elf64Ehdr, Elf64Phdr, Elf64Rela, Elf64Sym, PF_X, - PT_DYNAMIC, PT_LOAD, R_X86_64_64, R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT, R_X86_64_NONE, - R_X86_64_RELATIVE, SHN_UNDEF, STB_WEAK, + PT_DYNAMIC, PT_LOAD, R_AARCH64_ABS64, R_AARCH64_GLOB_DAT, R_AARCH64_JUMP_SLOT, + R_AARCH64_NONE, R_AARCH64_RELATIVE, R_X86_64_64, R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT, + R_X86_64_NONE, R_X86_64_RELATIVE, SHN_UNDEF, STB_WEAK, }, util::{align_down, align_up}, }; @@ -30,9 +42,14 @@ pub fn get_vaddr(phdr: *const Elf64Phdr, load_bias: u64) -> *mut u8 { unsafe { ((*phdr).p_vaddr + load_bias) as *mut u8 } } +#[cfg(target_arch = "aarch64")] +type PageTable = AArchPageTable; + #[cfg(target_arch = "x86_64")] +type PageTable<'a> = OffsetPageTable<'a>; + pub unsafe fn load_program( - mapper: &mut OffsetPageTable, + mapper: &mut PageTable, hdr: *const Elf64Ehdr, elf_bytes: &[u8], pie: bool, @@ -55,7 +72,6 @@ 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); } @@ -74,7 +90,7 @@ pub unsafe fn load_program( align_up(highest_seg as u64, 4096), ); } else { - let base_address = 0x0000_0100_0000; // TODO: add per-process memory + let base_address = 0x0000_0100_0000; let min_vaddr = align_down( program_headers .iter() @@ -98,7 +114,6 @@ 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); } @@ -124,30 +139,7 @@ pub unsafe fn load_program( } } -// fn cstr_from_strtab( -// strtab_ptr: *const u8, -// strtab_size: u64, -// off: u32, -// ) -> Option<&'static core::ffi::CStr> { -// let off = off as u64; -// if strtab_ptr.is_null() || off >= strtab_size { -// return None; -// } - -// let mut i = off; - -// while i < strtab_size { -// let b = unsafe { *strtab_ptr.add(i as usize) }; -// if b == 0 { -// let start = unsafe { strtab_ptr.add(off as usize) } as *const core::ffi::c_char; -// return Some(unsafe { CStr::from_ptr(start as *const i8) }); -// } -// i += 1; -// } - -// None -// } - +#[allow(unused_variables)] pub fn dyn_get_symaddr( strtab_ptr: *const u8, strtab_size: u64, @@ -160,12 +152,11 @@ pub fn dyn_get_symaddr( return Ok(load_bias + sym.st_value); } - // let name = cstr_from_strtab(strtab_ptr, strtab_size, idx as u32); - let bind = sym.st_info >> 4; if bind == STB_WEAK { Ok(0) } else { Err(()) } } +#[allow(unused_variables)] fn apply_relocations( hdr: *const Elf64Ehdr, rela_ptr: *mut Elf64Rela, @@ -178,12 +169,13 @@ fn apply_relocations( for i in 0..rela_table_size as usize / size_of::() { let rela_ptr = unsafe { rela_ptr.add(i) }; let ptr = unsafe { (load_bias + (*rela_ptr).r_offset) as *mut u64 }; + #[allow(unused_assignments)] let mut value: u64 = 0; match unsafe { ((*rela_ptr).r_info & 0xffff_ffff) as u32 } { - x if x == R_X86_64_RELATIVE as u32 => unsafe { + x if x == R_X86_64_RELATIVE || x == R_AARCH64_RELATIVE => unsafe { value = (load_bias as i64 + (*rela_ptr).r_addend) as u64; }, - x if x == R_X86_64_64 as u32 => unsafe { + x if x == R_X86_64_64 || x == R_AARCH64_ABS64 => unsafe { value = (dyn_get_symaddr( strtab_ptr, strtab_size, @@ -194,7 +186,14 @@ fn apply_relocations( .unwrap() as i64 + (*rela_ptr).r_addend) as u64; }, - x if [R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT].contains(&x) => unsafe { + x if [ + R_X86_64_GLOB_DAT, + R_X86_64_JUMP_SLOT, + R_AARCH64_GLOB_DAT, + R_AARCH64_JUMP_SLOT, + ] + .contains(&x) => + unsafe { value = dyn_get_symaddr( strtab_ptr, strtab_size, @@ -204,7 +203,7 @@ fn apply_relocations( ) .unwrap() as u64; }, - x if x == R_X86_64_NONE as u32 => { + x if x == R_X86_64_NONE || x == R_AARCH64_NONE => { continue; // explicitly do nothing } _ => { @@ -279,9 +278,8 @@ fn parse_dyn( ); } -#[cfg(target_arch = "x86_64")] pub fn load_segment_to_memory( - mapper: &mut OffsetPageTable, + mapper: &mut PageTable, phdr: *const Elf64Phdr, elf_bytes: &[u8], load_bias: u64, @@ -300,40 +298,38 @@ pub fn load_segment_to_memory( let vaddr: u64 = get_vaddr(phdr, load_bias) as u64; let mem_page: u64 = align_down(vaddr, PAGE_SIZE); - let file_page: u64 = align_down(p_offset, PAGE_SIZE); let page_off: u64 = vaddr - mem_page; let seg_start = mem_page; let seg_end = align_up(vaddr + mem_size, PAGE_SIZE); - let mut flags = - PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::WRITABLE; + #[cfg(target_arch = "x86_64")] + { + let mut flags = + PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | PageTableFlags::WRITABLE; - if unsafe { ((*phdr).p_flags & PF_X) == 0 } { - flags |= PageTableFlags::NO_EXECUTE; - } - - let start_page: Page = Page::containing_address(VirtAddr::new(seg_start)); - let end_page: Page = Page::containing_address(VirtAddr::new(seg_end - 1)); - let page_range = Page::range_inclusive(start_page, end_page); - - let mut frame_allocator = FRAME_ALLOCATOR.lock(); - - for page in page_range { - let frame = frame_allocator - .allocate_frame() - .ok_or(MapToError::::FrameAllocationFailed) - .expect("test"); - unsafe { - mapper - .map_to(page, frame, flags, &mut *frame_allocator) - .map_err(|e| e) - .expect("test") - .flush(); + if unsafe { ((*phdr).p_flags & PF_X) == 0 } { + flags |= PageTableFlags::NO_EXECUTE; } - } - drop(frame_allocator); + let map_start = seg_start; + let page_count = (seg_end - seg_start) / 4096; + + create_and_map_multiple_pages(mapper, page_count, map_start, flags); + } + #[cfg(target_arch = "aarch64")] + { + let mut flags = user_code_flags(); + + if unsafe { ((*phdr).p_flags & PF_X) == 0 } { + flags |= UXN; + } + + let map_start = seg_start; + let page_count = (seg_end - seg_start) / 4096; + + create_and_map_multiple_pages(mapper, page_count, map_start, flags); + } let dst = (mem_page + page_off) as *mut u8; let src = unsafe { elf_bytes.as_ptr().add(p_offset as usize) }; diff --git a/kernel/src/driver/fs/vfs.rs b/kernel/src/driver/fs/vfs.rs index 247f9af..1efe18f 100644 --- a/kernel/src/driver/fs/vfs.rs +++ b/kernel/src/driver/fs/vfs.rs @@ -141,6 +141,7 @@ pub fn vfs_close(fd: Fd) -> i32 { } #[unsafe(no_mangle)] +#[allow(unused_variables)] pub fn vfs_write(ptr: *mut u8, size: usize, count: usize, fp: *mut FILE) -> usize { if ptr.is_null() || fp.is_null() || unsafe { (*fp).fd < 0 || (*fp).fd >= 16 } { return 0; diff --git a/kernel/src/driver/graphics/framebuffer.rs b/kernel/src/driver/graphics/framebuffer.rs index ce47277..7650bb4 100644 --- a/kernel/src/driver/graphics/framebuffer.rs +++ b/kernel/src/driver/graphics/framebuffer.rs @@ -33,7 +33,6 @@ impl Framebuffer { let width = limine_fb.width() as usize; let height = limine_fb.height() as usize; let pitch = limine_fb.pitch() as usize / 4; - Framebuffer { addr: limine_fb.addr().cast::(), width, @@ -55,7 +54,7 @@ impl Framebuffer { #[cfg(target_arch = "x86_64")] pub fn setup_x86_64(&mut self) { - use crate::arch::arch::FRAME_ALLOCATOR; + use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET}; use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB}; let buf_len = self.pitch * self.height; let byte_len = buf_len * core::mem::size_of::(); @@ -66,7 +65,8 @@ impl Framebuffer { let struct_frame: PhysFrame = fa.allocate_frame().expect("framebuffer struct frame"); let struct_phys = struct_frame.start_address().as_u64(); - let struct_virt = (struct_phys + fa.hhdm_offset) as *mut UserFrameBuffer; + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); + let struct_virt = (struct_phys + hhdm_offset) as *mut UserFrameBuffer; let first_pixel_frame: PhysFrame = fa.allocate_frame().expect("framebuffer pixel frame 0"); @@ -74,7 +74,44 @@ impl Framebuffer { for _ in 1..pixel_frames { fa.allocate_frame().expect("framebuffer pixel frame"); } - let buf_virt_kernel = (buf_phys + fa.hhdm_offset) as *mut u32; + let buf_virt_kernel = (buf_phys + hhdm_offset) as *mut u32; + drop(fa); + + unsafe { core::ptr::write_bytes(buf_virt_kernel, 0, buf_len) }; + + unsafe { + struct_virt.write(UserFrameBuffer { + buf_virt: (USER_FB_BASE + 0x1000) as *mut u32, + width: self.width, + height: self.height, + pitch: self.pitch, + }); + }; + + 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; + } + + #[cfg(target_arch = "aarch64")] + pub fn setup_aarch64(&mut self) { + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); + use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET}; + 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 = safe_lock(|| FRAME_ALLOCATOR.lock()); + + let struct_phys: u64 = fa.allocate_frame().expect("framebuffer struct frame"); + let struct_virt = (struct_phys + hhdm_offset) as *mut UserFrameBuffer; + + let buf_phys: u64 = fa.allocate_frame().expect("framebuffer pixel frame 0"); + for _ in 1..pixel_frames { + fa.allocate_frame().expect("framebuffer pixel frame"); + } + let buf_virt_kernel = (buf_phys + hhdm_offset) as *mut u32; drop(fa); unsafe { core::ptr::write_bytes(buf_virt_kernel, 0, buf_len) }; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 99b9992..6cba699 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -7,8 +7,8 @@ use core::fmt::Write; use limine::BaseRevision; use limine::request::{ - DateAtBootRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, RequestsEndMarker, - RequestsStartMarker, + DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest, + RequestsEndMarker, RequestsStartMarker, }; pub mod arch; pub mod driver; @@ -16,17 +16,23 @@ pub mod mm; pub mod task; pub mod util; -use crate::arch::arch::{infinite_idle, init, kernel_crash, run_elf}; +use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_print}; +#[cfg(target_arch = "x86_64")] +use crate::driver::elf::loader::run_elf; use crate::driver::graphics::base::rgb; use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer}; +#[cfg(target_arch = "aarch64")] +use crate::driver::graphics::primitives::rectangle_filled; 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))] +#[allow(dead_code)] struct AlignedElf([u8; include_bytes!("../../assets/init").len()]); +#[allow(dead_code)] static INIT_ELF: AlignedElf = AlignedElf(*include_bytes!("../../assets/init")); +#[allow(dead_code)] static INIT_ELF_BYTES: &[u8] = &INIT_ELF.0; /// Sets the base revision to the latest revision supported by the crate. @@ -53,6 +59,10 @@ 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 EXECUTABLE_ADDRESS_REQUEST: ExecutableAddressRequest = ExecutableAddressRequest::new(); + /// Define the stand and end markers for Limine requests. #[used] #[unsafe(link_section = ".requests_start_marker")] @@ -99,8 +109,24 @@ unsafe extern "C" fn kmain() -> ! { assert!(BASE_REVISION.is_supported()); if let Some(hhdm_response) = HHDM_REQUEST.get_response() { + HHDM_OFFSET.store( + hhdm_response.offset(), + core::sync::atomic::Ordering::Relaxed, + ); if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() { + #[cfg(target_arch = "x86_64")] init(hhdm_response, memory_map_response); + + #[cfg(target_arch = "aarch64")] + if let Some(executable_address_response) = EXECUTABLE_ADDRESS_REQUEST.get_response() { + init( + hhdm_response, + memory_map_response, + executable_address_response, + ); + } else { + kernel_crash() + } } else { kernel_crash(); // Could not get required info from Limine's memory map. } @@ -113,6 +139,10 @@ unsafe extern "C" fn kmain() -> ! { init_framebuffer(&limine_framebuffer); #[cfg(target_arch = "x86_64")] with_framebuffer(|fb| fb.setup_x86_64()); + #[cfg(target_arch = "aarch64")] + with_framebuffer(|fb| fb.setup_aarch64()); + } else { + serial_print("no framebuffers found"); } } @@ -126,20 +156,56 @@ unsafe extern "C" fn kmain() -> ! { println!("Could not get date at boot. Will default to 0.") } + #[cfg(target_arch = "aarch64")] + { + println!("Hello from Aarch64!"); + with_framebuffer(|fb| { + with_serial_console(|sc| sc.render(fb)); + rectangle_filled(fb, 100, 100, 20, 20, rgb(255, 255, 255)); + fb.present(); + }); + } + #[cfg(target_arch = "x86_64")] run_elf(INIT_ELF_BYTES, false); loop {} } +struct BufWriter<'a> { + buf: &'a mut [u8], + pos: usize, +} + +impl<'a> BufWriter<'a> { + fn new(buf: &'a mut [u8]) -> Self { + Self { buf, pos: 0 } + } +} + +impl core::fmt::Write for BufWriter<'_> { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let bytes = s.as_bytes(); + let remaining = &mut self.buf[self.pos..]; + let len = bytes.len().min(remaining.len()); + remaining[..len].copy_from_slice(&bytes[..len]); + self.pos += len; + Ok(()) + } +} + #[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"); - } + serial_print("\nKERNEL PANIC:\n"); + let mut buf = [0u8; 512]; + let msg = { + let mut w = BufWriter::new(&mut buf); + let _ = core::fmt::write(&mut w, core::format_args!("{}", _info.message())); + let len = w.pos; + core::str::from_utf8(&buf[..len]).unwrap_or("(utf8 error)") + }; + serial_print(msg); + 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 12bbdc5..8d0ecb2 100644 --- a/kernel/src/mm/address_space.rs +++ b/kernel/src/mm/address_space.rs @@ -2,19 +2,34 @@ use x86_64::{ PhysAddr, VirtAddr, registers::control::{Cr3, Cr3Flags}, - structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB}, + structures::paging::{ + FrameAllocator, OffsetPageTable, PageTable as X86PageTable, PhysFrame, Size4KiB, + }, }; -use crate::arch::arch::FRAME_ALLOCATOR; +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::paging::{AArchPageTable, tlb_flush}; + +#[cfg(target_arch = "x86_64")] +use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET}; + +#[cfg(target_arch = "aarch64")] +type PageTable = AArchPageTable; + +#[cfg(target_arch = "x86_64")] +type PageTable<'a> = OffsetPageTable<'a>; #[cfg(target_arch = "x86_64")] pub struct AddressSpace { cr3_frame: PhysFrame, - pub mapper: OffsetPageTable<'static>, + pub mapper: PageTable<'static>, } #[cfg(target_arch = "aarch64")] -pub struct AddressSpace {} +pub struct AddressSpace { + ttbr0_phys: u64, + pub mapper: PageTable, +} #[cfg(target_arch = "x86_64")] impl AddressSpace { @@ -22,19 +37,17 @@ impl AddressSpace { let mut frame_allocator = FRAME_ALLOCATOR.lock(); let new_pml4 = frame_allocator.allocate_frame()?; + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); unsafe { - let new_pml4_ptr = - (frame_allocator.hhdm_offset + new_pml4.start_address().as_u64()) as *mut u64; + let new_pml4_ptr = (hhdm_offset + new_pml4.start_address().as_u64()) as *mut u64; core::ptr::write_bytes(new_pml4_ptr, 0, 512); } let (cur_pml4, _) = Cr3::read(); unsafe { - let cur_pml4_ptr = - physical_to_virt_pointer(cur_pml4.start_address(), frame_allocator.hhdm_offset); - let new_pml4_ptr = - physical_to_virt_pointer(new_pml4.start_address(), frame_allocator.hhdm_offset); + let cur_pml4_ptr = physical_to_virt_pointer(cur_pml4.start_address()); + let new_pml4_ptr = physical_to_virt_pointer(new_pml4.start_address()); for i in 256..512 { let val = core::ptr::read(cur_pml4_ptr.add(i)); @@ -43,13 +56,10 @@ impl AddressSpace { } let mapper = unsafe { - let addr = frame_allocator.hhdm_offset + new_pml4.start_address().as_u64(); + let addr = hhdm_offset + new_pml4.start_address().as_u64(); let virtual_addr = VirtAddr::new(addr); - let level_4_table: *mut PageTable = virtual_addr.as_mut_ptr(); - OffsetPageTable::new( - &mut *level_4_table, - VirtAddr::new(frame_allocator.hhdm_offset), - ) + let level_4_table: *mut X86PageTable = virtual_addr.as_mut_ptr(); + OffsetPageTable::new(&mut *level_4_table, VirtAddr::new(hhdm_offset)) }; drop(frame_allocator); @@ -65,7 +75,31 @@ impl AddressSpace { } } +#[cfg(target_arch = "aarch64")] +impl AddressSpace { + pub fn new() -> Option { + let page_table = AArchPageTable::new(); + let ttbr0_phys = page_table.root_phys; + Some(AddressSpace { + ttbr0_phys, + mapper: page_table, + }) + } + pub fn use_address_space(&mut self) { + unsafe { + core::arch::asm!( + "msr ttbr0_el1, {root}", + "isb", + root = in(reg) self.ttbr0_phys + ); + } + + tlb_flush(); + } +} + #[cfg(target_arch = "x86_64")] -pub unsafe fn physical_to_virt_pointer(phys_addr: PhysAddr, hhdm_offset: u64) -> *mut u64 { +pub unsafe fn physical_to_virt_pointer(phys_addr: PhysAddr) -> *mut u64 { + let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed); (hhdm_offset + phys_addr.as_u64()) as *mut u64 } diff --git a/kernel/src/mm/usercopy.rs b/kernel/src/mm/usercopy.rs index fa6f510..9f73f1e 100644 --- a/kernel/src/mm/usercopy.rs +++ b/kernel/src/mm/usercopy.rs @@ -9,45 +9,65 @@ use x86_64::{ structures::paging::{OffsetPageTable, PageTableFlags, Translate, mapper::TranslateResult}, }; +#[cfg(target_arch = "aarch64")] +use crate::arch::aarch64::paging::AArchPageTable; + +#[cfg(target_arch = "aarch64")] +type PageTable = AArchPageTable; + #[cfg(target_arch = "x86_64")] +type PageTable<'a> = OffsetPageTable<'a>; + +#[allow(unused_variables)] pub fn copy_to_user( - mapper: &mut OffsetPageTable, + mapper: &mut PageTable, buf: *mut u8, src: *const u8, len: usize, ) -> Result<(), isize> { let start = buf as u64; let end = start + len as u64; + #[allow(unused_mut)] let mut page_addr = start & !0xFFF; - while page_addr < end { - let translate_result = mapper.translate(VirtAddr::new(page_addr)); - #[allow(non_shorthand_field_patterns)] - if let TranslateResult::Mapped { - frame: _, - offset: _, - flags: flags, - } = translate_result - { - if flags.contains(PageTableFlags::USER_ACCESSIBLE) - && flags.contains(PageTableFlags::WRITABLE) + #[cfg(target_arch = "x86_64")] + { + while page_addr < end { + let translate_result = mapper.translate(VirtAddr::new(page_addr)); + #[allow(non_shorthand_field_patterns)] + if let TranslateResult::Mapped { + frame: _, + offset: _, + flags: flags, + } = translate_result { + if flags.contains(PageTableFlags::USER_ACCESSIBLE) + && flags.contains(PageTableFlags::WRITABLE) + { + } else { + return Err(-13); + } } else { - return Err(-13); + return Err(-1); } - } else { - return Err(-1); + page_addr += 0x1000; } - page_addr += 0x1000; + + unsafe { core::ptr::copy_nonoverlapping(src, buf, len) }; + } + + #[cfg(target_arch = "aarch64")] + { + // TODO: add checks + unsafe { core::ptr::copy_nonoverlapping(src, buf, len) }; } - unsafe { core::ptr::copy_nonoverlapping(src, buf, len) }; Ok(()) } -#[cfg(target_arch = "x86_64")] +#[allow(unused_variables)] pub fn copy_from_user( - mapper: &mut OffsetPageTable, + mapper: &mut PageTable, buf: *mut u8, src: *const u8, len: usize, @@ -64,34 +84,43 @@ pub fn copy_from_user( .checked_add(len as u64) .ok_or(-1) .map_err(|err| err as isize)?; - + #[allow(unused_mut)] let mut page_addr = start & !0xFFF; - while page_addr < end { - let translate_result = mapper.translate(VirtAddr::new(page_addr)); - #[allow(non_shorthand_field_patterns)] - if let TranslateResult::Mapped { - frame: _, - offset: _, - flags: flags, - } = translate_result - { - if !flags.contains(PageTableFlags::USER_ACCESSIBLE) { - return Err(-13); + #[cfg(target_arch = "x86_64")] + { + while page_addr < end { + let translate_result = mapper.translate(VirtAddr::new(page_addr)); + #[allow(non_shorthand_field_patterns)] + if let TranslateResult::Mapped { + frame: _, + offset: _, + flags: flags, + } = translate_result + { + if !flags.contains(PageTableFlags::USER_ACCESSIBLE) { + return Err(-13); + } + } else { + return Err(-1); } - } else { - return Err(-1); + page_addr += 0x1000; } - page_addr += 0x1000; + + unsafe { core::ptr::copy_nonoverlapping(src, buf, len) }; + } + + #[cfg(target_arch = "aarch64")] + { + // TODO: add checks + unsafe { core::ptr::copy_nonoverlapping(src, buf, len) }; } - unsafe { core::ptr::copy_nonoverlapping(src, buf, len) }; Ok(()) } -#[cfg(target_arch = "x86_64")] pub fn copy_cstr_from_user( - mapper: &mut OffsetPageTable, + mapper: &mut PageTable, user_ptr: *const u8, max_len: usize, ) -> Result { diff --git a/kernel/src/task/context.rs b/kernel/src/task/context.rs index a5dc2b7..9584ca3 100644 --- a/kernel/src/task/context.rs +++ b/kernel/src/task/context.rs @@ -1,5 +1,6 @@ use crate::task::scheduler::{SCHEDULER, current_pid}; +#[cfg(target_arch = "x86_64")] #[repr(C)] #[derive(Clone, Copy)] pub struct UserContext { @@ -22,6 +23,11 @@ pub struct UserContext { pub rsp: u64, // user rsp } +#[cfg(target_arch = "aarch64")] +#[repr(C)] +#[derive(Clone, Copy)] +pub struct UserContext {} + #[unsafe(no_mangle)] pub extern "C" fn ctx_save(regs: *const UserContext) { if let Some(pid) = current_pid() { diff --git a/kernel/src/task/scheduler.rs b/kernel/src/task/scheduler.rs index 98c1a12..da8dc92 100644 --- a/kernel/src/task/scheduler.rs +++ b/kernel/src/task/scheduler.rs @@ -86,7 +86,6 @@ 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 = safe_lock(|| self.lock()); @@ -117,7 +116,9 @@ impl Locked { set_current_pid(Some(pid)); match ctx_opt { + #[allow(unused_variables, unused_unsafe)] Some(saved_ctx) => unsafe { + #[cfg(target_arch = "x86_64")] run_next((&saved_ctx) as *const UserContext, saved_ctx.rsp) }, None => enter_usermode(entry as u64, (stack_top & !0xF) - 8, should_swapgs), @@ -163,3 +164,11 @@ unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) { "sysretq", ); } + +#[cfg(target_arch = "aarch64")] +#[unsafe(naked)] +#[unsafe(no_mangle)] +unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) { + // TODO: add switching logic + core::arch::naked_asm!("udf #0"); +} diff --git a/kernel/src/util.rs b/kernel/src/util.rs index 9d3394b..d55cbb6 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -5,20 +5,6 @@ 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 { diff --git a/user/libxunil b/user/libxunil index da6f056..695da84 160000 --- a/user/libxunil +++ b/user/libxunil @@ -1 +1 @@ -Subproject commit da6f056359e682655623723873c54f7f4c59bcdb +Subproject commit 695da849016f98f7a28b69c800bb33c0e49fc202