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
This commit is contained in:
csd4ni3l
2026-05-16 00:30:01 +02:00
parent 17f2a3c7e4
commit 812d4cf6d4
32 changed files with 911 additions and 405 deletions
+1
View File
@@ -1,4 +1,5 @@
/limine
/.zed
/edk2-ovmf
*.iso
*.hdd
+1
View File
@@ -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
+10 -18
View File
@@ -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/ : {
+22 -1
View File
@@ -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<LinkedListAllocator> = 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);
}
}
+21 -2
View File
@@ -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;
}
+1
View File
@@ -0,0 +1 @@
// TODO: add interrupts
+1
View File
@@ -0,0 +1 @@
// TODO: add keyboard logic
+4
View File
@@ -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;
+1
View File
@@ -0,0 +1 @@
// TODO: add mouse logic
+277 -1
View File
@@ -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<XunilFrameAllocator> =
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<u64> {
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<u64> {
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);
}
+1
View File
@@ -0,0 +1 @@
// TODO: add syscalls
+15
View File
@@ -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)
)
};
}
+62 -29
View File
@@ -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: FnOnce() -> R>(f: F) -> R {
@@ -121,6 +128,32 @@ pub fn safe_lock<R, F: FnOnce() -> 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")]
+54 -81
View File
@@ -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::<Size4KiB>::containing_address(PhysAddr::new(phys));
let page = Page::<Size4KiB>::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::<Size4KiB>::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::<u8>(), 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,
-62
View File
@@ -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::<Size4KiB>::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;
};
}
+11 -30
View File
@@ -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<Size4KiB>> {
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<Size4KiB> = Page::containing_address(page_start);
let heap_end_page: Page<Size4KiB> = 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::<Size4KiB>::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);
+12 -19
View File
@@ -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
}
-1
View File
@@ -1,4 +1,3 @@
pub mod elf;
pub mod gdt;
pub mod heap;
pub mod init;
+35 -4
View File
@@ -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<Size4KiB> 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<Size4KiB> 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::<Size4KiB>::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<XunilFrameAllocator> =
Mutex::new(XunilFrameAllocator::new());
+3 -3
View File
@@ -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)
);
}
+7
View File
@@ -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;
+60 -6
View File
@@ -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;
};
}
+60 -64
View File
@@ -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::<Elf64Rela>() {
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<Size4KiB> = Page::containing_address(VirtAddr::new(seg_start));
let end_page: Page<Size4KiB> = 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::<Size4KiB>::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) };
+1
View File
@@ -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;
+41 -4
View File
@@ -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::<u32>(),
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::<u32>();
@@ -66,7 +65,8 @@ impl Framebuffer {
let struct_frame: PhysFrame<Size4KiB> =
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<Size4KiB> =
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::<u32>();
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) };
+76 -10
View File
@@ -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));
+51 -17
View File
@@ -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<Size4KiB>,
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<AddressSpace> {
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
}
+66 -37
View File
@@ -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<String, isize> {
+6
View File
@@ -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() {
+10 -1
View File
@@ -86,7 +86,6 @@ impl Locked<Scheduler> {
};
}
#[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<Scheduler> {
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");
}
-14
View File
@@ -5,20 +5,6 @@ pub struct Locked<A> {
inner: Mutex<A>,
}
#[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<A> Locked<A> {
pub const fn new(inner: A) -> Self {
Locked {