Improve aarch64 support by building everything for both archictectures,

remove incorrect timer frequency set, fix interrupt handler not
restoring stack ptr, handle both user and kernel aborts, remove aarch64
ps2 support, fix ELF code mapped as code making it unwritable, add
assets.rs to handle both arches automatically, make PS2 x86_64
compatible with linux keycodes, always try printing kernel panic to
serial
This commit is contained in:
csd4ni3l
2026-05-22 22:18:42 +02:00
parent 1205d8ce7a
commit 56c5da0742
40 changed files with 393 additions and 301 deletions
+3 -2
View File
@@ -12,7 +12,7 @@ ifeq ($(RUST_TARGET),)
endif
ifeq ($(RUST_PROFILE),)
override RUST_PROFILE := dev
override RUST_PROFILE := release
endif
override RUST_PROFILE_SUBDIR := $(RUST_PROFILE)
@@ -23,7 +23,8 @@ endif
# Default target.
.PHONY: all
all:
RUSTFLAGS="-C relocation-model=static" cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE)
RUSTFLAGS="-C relocation-model=static" cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE) --config profile.release.debug=true
cp target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR)/$$(cd target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR) && find -maxdepth 1 -perm -111 -type f) kernel
# Remove object files and the final executable.
+8
View File
@@ -15,6 +15,14 @@ fn main() {
)
.unwrap();
let out_dir = out_dir.join("driver").join("io").join("fs");
fs::write(
out_dir.join("assets.rs"),
format!("pub static INIT_ELF: &[u8] = include_bytes!(\"../../../../../assets/{karch}/init\");\npub static DOOM_WAD: &[u8] = include_bytes!(\"../../../../../assets/doom1.wad\");\npub static DOOM_ELF: &[u8] = include_bytes!(\"../../../../../assets/{karch}/doomgeneric\");\npub static HELLOWORLD_ELF: &[u8] = include_bytes!(\"../../../../../assets/{karch}/helloworld.elf\");"),
)
.unwrap();
println!("cargo:rerun-if-env-changed=KARCH");
println!("cargo:rerun-if-env-changed=TIMER_FREQUENCY_HZ");
println!("cargo:rerun-if-env-changed=OUTPUT");
+2 -10
View File
@@ -4,8 +4,7 @@ use crate::{
interrupts::init_interrupts,
paging::{AArchPageTable, initialize_paging_aarch64},
},
config::TIMER_FREQUENCY_HZ,
driver::io::virtio::scan_devices,
driver::io::virtio::scan_virtio_devices,
};
use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse};
@@ -15,12 +14,6 @@ pub struct Stack(pub [u8; 64 * 1024]);
pub static KERNEL_STACK: Stack = Stack([0; 64 * 1024]);
pub fn set_timer_freq(freq: usize) {
unsafe {
core::arch::asm!("mrs {}, cntp_tval_el0", "isb", in(reg) freq);
}
}
#[unsafe(naked)]
pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) {
// fix stack, since limine's bootloader stack is not mapped
@@ -38,8 +31,7 @@ pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) {
#[unsafe(no_mangle)]
pub extern "C" fn init_aarch64(mapper: &mut AArchPageTable) {
init_heap(mapper);
set_timer_freq(TIMER_FREQUENCY_HZ);
scan_devices();
scan_virtio_devices();
init_interrupts();
}
+61 -19
View File
@@ -1,7 +1,7 @@
use core::{arch::global_asm, sync::atomic::Ordering};
use crate::{
arch::syscall::syscall_dispatch,
arch::syscall::{check_and_reschedule, syscall_dispatch},
config::TIMER_FREQUENCY_HZ,
driver::{
graphics::framebuffer::with_framebuffer,
@@ -9,11 +9,9 @@ use crate::{
serial::with_serial_console,
timer::TIMER,
},
task::context::UserContext,
task::context::{UserContext, ctx_save},
};
use aarch64_cpu::registers::{DAIF, Writeable};
global_asm!(
r#"
.section .text.vectors
@@ -43,6 +41,12 @@ global_asm!(
"#
);
fn timer_ticks_per_irq() -> u64 {
let cntfrq: u64;
unsafe { core::arch::asm!("mrs {}, cntfrq_el0", out(reg) cntfrq) };
cntfrq / (TIMER_FREQUENCY_HZ as u64)
}
// stp allows storing in pairs, ldp loads in pairs
macro_rules! exception_handler {
($name:ident, $rust_handler:ident) => {
@@ -66,6 +70,8 @@ macro_rules! exception_handler {
"stp x24, x25, [sp, #192]",
"stp x26, x27, [sp, #208]",
"stp x28, x29, [sp, #224]",
"mrs x2, sp_el0",
"str x2, [sp, #280]",
"mrs x0, elr_el1",
"mrs x1, spsr_el1",
"stp x30, x0, [sp, #240]",
@@ -75,6 +81,8 @@ macro_rules! exception_handler {
"stp x2, x3, [sp, #264]",
"mov x0, sp",
concat!("bl ", stringify!($rust_handler)),
"ldr x2, [sp, #280]",
"msr sp_el0, x2",
"ldr x1, [sp, #256]",
"ldp x30, x0, [sp, #240]",
"msr spsr_el1, x1",
@@ -155,6 +163,7 @@ unsafe fn gic_eoi(id: u32) {
pub fn init_interrupts() {
unsafe { use_exception_vectors() };
unsafe { gic_init() };
enable_interrupts();
unsafe { core::arch::asm!("isb") };
}
@@ -168,14 +177,14 @@ pub fn enable_interrupts() {
gic_enable_interrupt(keyboard_irq as u32);
gic_enable_interrupt(mouse_irq as u32);
let ticks = timer_ticks_per_irq();
core::arch::asm!("msr cntp_tval_el0, {}", in(reg) ticks);
core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64); // enable timer
}
DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked);
}
#[allow(unused_variables, dead_code)]
#[unsafe(no_mangle)]
unsafe extern "C" fn no_operation(ctx: *mut UserContext) {
let interrupt_id = unsafe { gic_acknowledge() };
@@ -200,15 +209,14 @@ unsafe extern "C" fn irq_handler(ctx: *mut UserContext) {
if t % 60 == 0 {
with_framebuffer(|fb| {
with_serial_console(|serial_console| {
serial_console.print(".", fb);
serial_console.render(fb)
});
with_serial_console(|serial_console| serial_console.render(fb));
fb.present();
});
}
unsafe { core::arch::asm!("msr cntp_tval_el0, {}", in(reg) TIMER_FREQUENCY_HZ) };
let ticks = timer_ticks_per_irq();
unsafe { core::arch::asm!("msr cntp_tval_el0, {}", in(reg) ticks) };
unsafe { core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64) };
}
interrupt_id if keyboard_irq == interrupt_id as u64 => {
input_interrupt("kbd");
@@ -227,13 +235,13 @@ unsafe extern "C" fn irq_handler(ctx: *mut UserContext) {
fn handle_aborts(ec: u64, ctx: &UserContext) {
match ec {
0x25 => {
ec if ec == 0x25 || ec == 0x24 => {
panic!(
"Data abort at VA={:#x} ELR={:#x} ESR={:#x}",
ctx.far_el1, ctx.elr_el1, ctx.esr_el1
);
}
0x21 => {
ec if ec == 0x21 || ec == 0x20 => {
panic!(
"Instruction abort at VA={:#x} ELR={:#x}",
ctx.far_el1, ctx.elr_el1
@@ -241,8 +249,8 @@ fn handle_aborts(ec: u64, ctx: &UserContext) {
}
_ => {
panic!(
"Unhandled sync abort VA={:#x} ELR={:#x} ESR={:#x}",
ctx.far_el1, ctx.elr_el1, ctx.esr_el1
"Unhandled sync abort VA={:#x} ELR={:#x} ESR={:#x}, ec={:#x}",
ctx.far_el1, ctx.elr_el1, ctx.esr_el1, ec
);
}
}
@@ -250,10 +258,9 @@ fn handle_aborts(ec: u64, ctx: &UserContext) {
#[unsafe(no_mangle)]
unsafe extern "C" fn sync_handler_user(ctx: *mut UserContext) {
let mut ctx = unsafe { *ctx };
let ctx = unsafe { &mut *ctx };
let ec = (ctx.esr_el1 >> ESR_EC_SHIFT) & ESR_EC_MASK;
#[allow(unused_assignments)]
match ec {
EC_SVC_AA64 => {
ctx.x0 = unsafe {
@@ -267,9 +274,13 @@ unsafe extern "C" fn sync_handler_user(ctx: *mut UserContext) {
ctx.x5 as isize,
)
} as u64;
ctx_save(ctx as *const UserContext);
let _ = unsafe { check_and_reschedule() };
}
_ => handle_aborts(ec, &ctx),
}
_ => handle_aborts(ec, ctx),
};
}
#[unsafe(no_mangle)]
@@ -279,6 +290,37 @@ unsafe extern "C" fn sync_handler_kernel(ctx: *mut UserContext) {
handle_aborts(ec, &ctx)
}
#[unsafe(naked)]
#[unsafe(no_mangle)]
pub unsafe fn run_next(ctx: *const UserContext, user_sp: u64) {
core::arch::naked_asm!(
"mov x30, x0",
"msr sp_el0, x1",
"ldr x2, [x30, #248]",
"msr elr_el1, x2",
"ldr x3, [x30, #256]",
"msr spsr_el1, x3",
"ldp x0, x1, [x30, #0]",
"ldp x2, x3, [x30, #16]",
"ldp x4, x5, [x30, #32]",
"ldp x6, x7, [x30, #48]",
"ldp x8, x9, [x30, #64]",
"ldp x10, x11, [x30, #80]",
"ldp x12, x13, [x30, #96]",
"ldp x14, x15, [x30, #112]",
"ldp x16, x17, [x30, #128]",
"ldp x18, x19, [x30, #144]",
"ldp x20, x21, [x30, #160]",
"ldp x22, x23, [x30, #176]",
"ldp x24, x25, [x30, #192]",
"ldp x26, x27, [x30, #208]",
"ldp x28, x29, [x30, #224]",
"ldr x30, [x30, #240]",
"isb",
"eret"
);
}
// these are UB and should not happen
exception_handler!(current_el_sp0_sync, no_operation);
exception_handler!(current_el_sp0_irq, no_operation);
-87
View File
@@ -1,87 +0,0 @@
use crate::arch::arch::safe_lock;
const KMI0_BASE: u64 = 0xFFFF_0000_0905_0000;
const KMI1_BASE: u64 = 0xFFFF_0000_0906_0000;
const KMI_CR: u64 = 0x00;
const KMI_STAT: u64 = 0x04;
const KMI_DATA: u64 = 0x08;
pub unsafe fn kmi_write(base: u64, kmi_type: u64, val: u8) {
let data = (base + kmi_type) as *mut u32;
unsafe { data.write_volatile(val as u32) };
}
pub fn kmi_read(base: u64, kmi_type: u64) -> u8 {
let data = (base + kmi_type) as *const u32;
unsafe { data.read_volatile() as u8 }
}
pub unsafe fn read_mouse_control() -> u8 {
kmi_read(KMI1_BASE, KMI_STAT)
}
pub unsafe fn read_mouse_data() -> u8 {
kmi_read(KMI1_BASE, KMI_DATA)
}
pub unsafe fn read_keyboard_control() -> u8 {
kmi_read(KMI0_BASE, KMI_STAT)
}
pub unsafe fn read_keyboard_data() -> u8 {
kmi_read(KMI0_BASE, KMI_DATA)
}
pub unsafe fn setup_kmi() -> u8 {
safe_lock(|| unsafe {
let cr0 = (KMI0_BASE + KMI_CR) as *mut u32;
cr0.write_volatile(0x14); // enable keyboard
kmi_write(KMI0_BASE, KMI_DATA, 0xFF); // reset keyboard
if kmi_read(KMI0_BASE, KMI_DATA) != 0xFA {
// ACK
return 2;
}
if kmi_read(KMI0_BASE, KMI_DATA) != 0xAA {
// self-test passed
return 3;
}
kmi_write(KMI0_BASE, KMI_DATA, 0xF4); // enable keyboard data reporting
if kmi_read(KMI0_BASE, KMI_DATA) != 0xFA {
// ACK
return 4;
}
let cr1 = (KMI1_BASE + KMI_CR) as *mut u32;
cr1.write_volatile(0x14); // enable mouse
kmi_write(KMI1_BASE, KMI_DATA, 0xFF); // reset mouse
if kmi_read(KMI1_BASE, KMI_DATA) != 0xFA {
// ACK
return 5;
}
if kmi_read(KMI1_BASE, KMI_DATA) != 0xAA {
// self-test passed
return 6;
}
if kmi_read(KMI1_BASE, KMI_DATA) != 0x00 {
// mouse ID
return 7;
}
kmi_write(KMI1_BASE, KMI_DATA, 0xF4); // enable mouse data reporting
if kmi_read(KMI1_BASE, KMI_DATA) != 0xFA {
// ACK
return 8;
}
return 9;
})
}
-2
View File
@@ -2,7 +2,5 @@ pub mod dtb;
pub mod heap;
pub mod init;
pub mod interrupts;
pub mod kmi;
pub mod paging;
pub mod syscall;
pub mod usermode;
+29 -17
View File
@@ -1,10 +1,11 @@
use core::sync::atomic::{AtomicBool, Ordering};
use core::sync::atomic::Ordering;
use crate::{
arch::{
aarch64::init::KERNEL_STACK,
arch::{HHDM_OFFSET, XunilFrameAllocator, safe_lock, serial_print},
},
driver::graphics::framebuffer::USER_FB_BASE,
util::U64Buf,
};
use limine::{
@@ -56,21 +57,12 @@ pub fn device_flags() -> u64 {
// no SH bits for device memory
}
static HHDM_OVERFLOW_REPORTED: AtomicBool = AtomicBool::new(false);
fn phys_to_virt(phys: u64) -> *mut u64 {
let hhdm_offset = HHDM_OFFSET.load(Ordering::Relaxed);
match phys.checked_add(hhdm_offset) {
Some(virt) => virt as *mut u64,
None => {
if !HHDM_OVERFLOW_REPORTED.swap(true, Ordering::Relaxed) {
serial_print("HHDM overflow phys=");
serial_print(U64Buf::new(phys).as_str());
serial_print(", hhdm_offset=");
serial_print(U64Buf::new(hhdm_offset).as_str());
serial_print("\n");
}
panic!("phys_to_virt overflow");
}
}
@@ -184,7 +176,8 @@ pub fn initialize_paging_aarch64<'a>(
page_table.map_range(0xFFFF_0000_0900_0000, 0x0900_0000, 0x1000, device_flags()); // the UART
page_table.map_range(0xFFFF_0000_0800_0000, 0x0800_0000, 0x10000, device_flags()); // the GICD
page_table.map_range(0xFFFF_0000_0801_0000, 0x0801_0000, 0x10000, device_flags()); // the GICC
page_table.map_range(0xFFFF_0000_0a00_0000, 0x0a00_0000, 0x8000, device_flags()); // Virtio setup_mair();
page_table.map_range(0xFFFF_0000_0a00_0000, 0x0a00_0000, 0x8000, device_flags()); // Virtio
setup_mair();
setup_tcr();
let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base;
@@ -259,6 +252,30 @@ impl AArchPageTable {
unsafe {
entry_ptr.write_volatile(phys | flags);
}
if virt == USER_FB_BASE + 0x1000 {
serial_print("entry_ptr=");
serial_print(U64Buf::new(entry_ptr as u64).as_str());
serial_print(", virt=");
serial_print(U64Buf::new(virt as u64).as_str());
serial_print(", phys=");
serial_print(U64Buf::new(phys as u64).as_str());
serial_print(", l0=");
serial_print(U64Buf::new(l0 as u64).as_str());
serial_print(", l1=");
serial_print(U64Buf::new(l1 as u64).as_str());
serial_print(", l2=");
serial_print(U64Buf::new(l2 as u64).as_str());
serial_print(", l3=");
serial_print(U64Buf::new(l3 as u64).as_str());
serial_print(", flags=");
serial_print(U64Buf::new(flags).as_str());
let written = unsafe { entry_ptr.read_volatile() };
serial_print(", readback=");
serial_print(U64Buf::new(written).as_str());
serial_print("\n");
}
}
pub fn map_range(&self, virt: u64, phys: u64, size: u64, flags: u64) {
@@ -302,17 +319,12 @@ pub fn create_and_map_multiple_pages(
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 frame = alloc_frame().unwrap();
let virt = base + i as u64 * 4096;
mapper.map_page(virt, frame, flags);
}
tlb_flush();
drop(frame_allocator);
}
-1
View File
@@ -1 +0,0 @@
// TODO: add syscalls
+30 -5
View File
@@ -11,6 +11,9 @@ use x86_64::{
structures::paging::{FrameAllocator, OffsetPageTable, PhysFrame, Size4KiB},
};
#[cfg(target_arch = "aarch64")]
use aarch64_cpu::registers::{DAIF, Writeable};
#[cfg(target_arch = "aarch64")]
pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR;
#[cfg(target_arch = "aarch64")]
@@ -91,8 +94,11 @@ impl XunilFrameAllocator {
}
#[cfg(target_arch = "x86_64")]
pub fn init<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {
init_x86_64(hhdm_response, memory_map_response);
pub fn init<'a>(
hhdm_response: &HhdmResponse,
memory_map_response: &'a MemoryMapResponse,
) -> OffsetPageTable<'a> {
init_x86_64(hhdm_response, memory_map_response)
}
#[cfg(target_arch = "aarch64")]
@@ -110,11 +116,26 @@ pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) {
enter_usermode_aarch64(entry, stack_ptr, should_swapgs);
}
#[cfg(target_arch = "x86_64")]
pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R {
#[cfg(target_arch = "x86_64")]
return without_interrupts(|| f());
#[cfg(target_arch = "aarch64")]
return f();
}
#[cfg(target_arch = "aarch64")]
pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R {
// #[cfg(target_arch = "aarch64")]
// {
// DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked);
// }
let r = f();
// #[cfg(target_arch = "aarch64")]
// {
// DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked);
// }
r
}
#[cfg(target_arch = "x86_64")]
@@ -157,6 +178,10 @@ pub fn idle() {
pub fn sleep(ticks: u64) {
let start = TIMER.now();
while start.ticks_since() < ticks {
#[cfg(target_arch = "aarch64")]
{
DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked);
}
idle();
}
}
+40 -7
View File
@@ -18,7 +18,7 @@ use crate::driver::io::ps2::process_scancodes;
#[cfg(target_arch = "aarch64")]
use crate::driver::io::virtio::input::process_keycodes;
use crate::{
arch::arch::{FRAME_ALLOCATOR, sleep},
arch::arch::{FRAME_ALLOCATOR, serial_print, sleep},
driver::{
elf::loader::run_elf,
graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer},
@@ -33,7 +33,7 @@ use crate::{
process::ProcessState,
scheduler::{SCHEDULER, current_pid},
},
util::{align_down, align_up},
util::{U64Buf, align_down, align_up},
};
use crate::{
@@ -363,7 +363,7 @@ pub fn exec(arg0: isize) -> isize {
return -1;
}
run_elf(&buf, true);
run_elf(&buf, true, false);
0
}
@@ -384,6 +384,7 @@ pub fn set_reschedule(should_reschedule: bool) {
}
pub fn exit() -> isize {
serial_print("Process Exited.");
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0;
@@ -414,6 +415,33 @@ pub fn exit() -> isize {
crate::arch::arch::infinite_idle();
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_and_reschedule() -> usize {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0;
}
let should = SCHEDULER
.with_process(pid, |process| process.should_reschedule)
.unwrap_or(false);
if !should {
return 0;
}
let next_task = SCHEDULER.next_task();
if next_task == pid {
return 0;
}
SCHEDULER.switch_to(next_task, true);
1
}
#[allow(unused_variables)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn syscall_dispatch(
@@ -427,20 +455,25 @@ pub unsafe extern "C" fn syscall_dispatch(
) -> isize {
#[cfg(target_arch = "x86_64")]
interrupts::enable();
// if num != 1 {
// serial_print("syscall num=");
// serial_print(U64Buf::new(num as u64).as_str());
// serial_print("\n");
// }
set_reschedule(match num {
BRK => false,
READ => true,
READ => false,
WRITE => false,
OPEN => true,
CLOSE => true,
LSEEK => true,
LSEEK => false,
EXIT => true,
SLEEP => true,
CLOCK_GETTIME => false,
MAP_FRAMEBUFFER => false,
KBD_READ => true,
FRAMEBUFFER_SWAP => true,
KBD_READ => false,
FRAMEBUFFER_SWAP => false,
GETPID => false,
EXECVE => true,
_ => false,
+1 -1
View File
@@ -9,7 +9,7 @@ use x86_64::structures::paging::{
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 const HEAP_SIZE: usize = 4 * 1024 * 1024; // 64 MiB
pub fn init_heap(mapper: &mut OffsetPageTable) -> Result<(), MapToError<Size4KiB>> {
let page_count = HEAP_SIZE / 4096;
+6 -1
View File
@@ -47,7 +47,10 @@ pub fn set_pit_interval() {
});
}
pub fn init_x86_64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a MemoryMapResponse) {
pub fn init_x86_64<'a>(
hhdm_response: &HhdmResponse,
memory_map_response: &'a MemoryMapResponse,
) -> OffsetPageTable<'a> {
load_gdt_x86_64();
unsafe {
@@ -87,4 +90,6 @@ pub fn init_x86_64<'a>(hhdm_response: &HhdmResponse, memory_map_response: &'a Me
.expect("Failed to initalize heap");
MOUSE.set_status(kmi_status);
return mapper;
}
+2 -1
View File
@@ -1,7 +1,7 @@
use core::sync::atomic::Ordering;
use crate::{
arch::x86_64::gdt,
arch::{arch::serial_print, x86_64::gdt},
driver::{
graphics::framebuffer::with_framebuffer,
io::ps2::{keyboard_interrupt, mouse_interrupt, push_scancode},
@@ -9,6 +9,7 @@ use crate::{
timer::TIMER,
},
println,
util::U64Buf,
};
use lazy_static::lazy_static;
use pic8259::ChainedPics;
+28 -28
View File
@@ -4,7 +4,7 @@ use x86_64::instructions::tlb::flush_all;
use crate::{
arch::x86_64::gdt::{GDT, TSS},
task::scheduler::{SCHEDULER, current_pid},
task::context::UserContext,
};
const IA32_EFER: u32 = 0xC0000080;
@@ -85,33 +85,6 @@ pub fn init_syscalls() {
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn check_and_reschedule() -> usize {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0;
}
let should = SCHEDULER
.with_process(pid, |process| process.should_reschedule)
.unwrap_or(false);
if !should {
return 0;
}
let next_task = SCHEDULER.next_task();
if next_task == pid {
return 0;
}
SCHEDULER.switch_to(next_task, false);
1
}
#[unsafe(naked)]
#[unsafe(no_mangle)]
unsafe extern "C" fn syscall_entry() {
@@ -206,3 +179,30 @@ unsafe extern "C" fn syscall_entry() {
"#,
);
}
#[unsafe(naked)]
#[unsafe(no_mangle)]
pub unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) {
core::arch::naked_asm!(
"mov gs:[0], rsi", // store new user rsp
"mov rsp, rdi",
"mov r15, qword ptr [rsp + 0]",
"mov r14, qword ptr [rsp + 8]",
"mov r13, qword ptr [rsp + 16]",
"mov r12, qword ptr [rsp + 24]",
"mov r11, qword ptr [rsp + 32]", // rflags
"mov r10, qword ptr [rsp + 40]",
"mov r9, qword ptr [rsp + 48]",
"mov r8, qword ptr [rsp + 56]",
"mov rsi, qword ptr [rsp + 64]",
"mov rdi, qword ptr [rsp + 72]",
"mov rbp, qword ptr [rsp + 80]",
"mov rdx, qword ptr [rsp + 88]",
"mov rcx, qword ptr [rsp + 96]", // rip
"mov rbx, qword ptr [rsp + 104]",
"mov rax, qword ptr [rsp + 112]",
"mov rsp, qword ptr [rsp + 120]", // user rsp
"swapgs",
"sysretq",
);
}
+1 -1
View File
@@ -1,2 +1,2 @@
pub const TIMER_FREQUENCY_HZ: usize = 1000;
pub const KARCH: &str = "aarch64";
pub const KARCH: &str = "x86_64";
+1
View File
@@ -144,6 +144,7 @@ pub const DT_VERNEED: i64 = 0x6ffffffe;
pub const DT_VERNEEDNUM: i64 = 0x6fffffff;
#[repr(C)]
#[derive(Debug)]
pub struct Elf64Ehdr {
pub e_ident: [u8; 16],
pub e_type: u16,
+5 -3
View File
@@ -59,7 +59,7 @@ pub fn load_file(mapper: &mut PageTable, elf_bytes: &[u8]) -> (*const u8, u64) {
unsafe { core::ptr::read_unaligned(elf_bytes.as_ptr() as *const Elf64Ehdr) };
if !validate_elf(&elf_header, elf_bytes.len()) {
return (null(), 0);
panic!("Invalid ELF");
}
let elf_header_ptr = elf_bytes.as_ptr() as *const Elf64Ehdr;
@@ -72,7 +72,7 @@ pub fn load_file(mapper: &mut PageTable, elf_bytes: &[u8]) -> (*const u8, u64) {
};
}
pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) {
pub fn run_elf(file_bytes: &[u8], should_swapgs: bool, switch_to: bool) {
let stack_base: u64 = 0x0000_7fff_0000_0000;
let page_count = 4096; // 16 mib
let page_size = 0x1000u64;
@@ -109,7 +109,9 @@ pub fn run_elf(file_bytes: &[u8], should_swapgs: bool) {
process.address_space = Some(address_space)
});
SCHEDULER.switch_to(process_pid, should_swapgs);
if switch_to {
SCHEDULER.switch_to(process_pid, should_swapgs);
}
} else {
return;
};
+6 -4
View File
@@ -21,7 +21,6 @@ use 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,
@@ -319,9 +318,13 @@ pub fn load_segment_to_memory(
}
#[cfg(target_arch = "aarch64")]
{
let mut flags = user_code_flags();
use crate::arch::aarch64::paging::user_data_flags;
if unsafe { ((*phdr).p_flags & PF_X) == 0 } {
let mut flags = user_data_flags();
if unsafe { ((*phdr).p_flags & PF_X) != 0 } {
flags &= !UXN;
} else {
flags |= UXN;
}
@@ -336,7 +339,6 @@ pub fn load_segment_to_memory(
unsafe {
core::ptr::copy_nonoverlapping(src, dst, file_size as usize);
if mem_size > file_size {
core::ptr::write_bytes(
dst.add(file_size as usize),
+42 -6
View File
@@ -1,5 +1,7 @@
use limine::framebuffer::Framebuffer as LimineFramebuffer;
use spin::Mutex;
#[cfg(target_arch = "x86_64")]
use x86_64::structures::paging::OffsetPageTable;
use crate::arch::arch::safe_lock;
@@ -53,9 +55,19 @@ impl Framebuffer {
}
#[cfg(target_arch = "x86_64")]
pub fn setup_x86_64(&mut self) {
use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET};
use x86_64::structures::paging::{FrameAllocator, PhysFrame, Size4KiB};
pub fn setup_x86_64(&mut self, mapper: &mut OffsetPageTable) {
use crate::{
arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET, serial_print},
arch::x86_64::paging::initialize_paging_x86_64,
util::U64Buf,
};
use x86_64::{
PhysAddr, VirtAddr,
structures::paging::{
FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB,
},
};
const KERNEL_FB_BASE: u64 = 0xffffffffa0000000;
let buf_len = self.pitch * self.height;
let byte_len = buf_len * core::mem::size_of::<u32>();
let pixel_frames = (byte_len + 4095) / 4096;
@@ -65,8 +77,6 @@ impl Framebuffer {
let struct_frame: PhysFrame<Size4KiB> =
fa.allocate_frame().expect("framebuffer struct frame");
let struct_phys = struct_frame.start_address().as_u64();
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 +84,33 @@ impl Framebuffer {
for _ in 1..pixel_frames {
fa.allocate_frame().expect("framebuffer pixel frame");
}
let buf_virt_kernel = (buf_phys + hhdm_offset) as *mut u32;
let hhdm_offset = HHDM_OFFSET.load(core::sync::atomic::Ordering::Relaxed);
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE;
let struct_page = Page::<Size4KiB>::containing_address(VirtAddr::new(KERNEL_FB_BASE));
unsafe {
mapper
.map_to(struct_page, struct_frame, flags, &mut *fa)
.unwrap()
.flush();
}
for i in 0..pixel_frames {
let frame = PhysFrame::<Size4KiB>::containing_address(PhysAddr::new(
buf_phys + i as u64 * 4096,
));
let page = Page::<Size4KiB>::containing_address(VirtAddr::new(
KERNEL_FB_BASE + 0x1000 + i as u64 * 4096,
));
unsafe {
mapper.map_to(page, frame, flags, &mut *fa).unwrap().flush();
}
}
let struct_virt = KERNEL_FB_BASE as *mut UserFrameBuffer;
let buf_virt_kernel = (KERNEL_FB_BASE + 0x1000) as *mut u32;
drop(fa);
unsafe { core::ptr::write_bytes(buf_virt_kernel, 0, buf_len) };
+4
View File
@@ -0,0 +1,4 @@
pub static INIT_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/init");
pub static DOOM_WAD: &[u8] = include_bytes!("../../../../../assets/doom1.wad");
pub static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/doomgeneric");
pub static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/helloworld.elf");
+1
View File
@@ -1 +1,2 @@
pub mod assets;
pub mod vfs;
+1 -4
View File
@@ -1,3 +1,4 @@
use crate::driver::io::fs::assets::*;
use core::ptr::{null, null_mut};
#[repr(C)]
@@ -38,10 +39,6 @@ fn fd_ok(fd: Fd) -> bool {
fd >= 0 && (fd as usize) < MAX_FD
}
static DOOM_WAD: &[u8] = include_bytes!("../../../../../assets/doom1.wad");
static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/doomgeneric");
static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/helloworld.elf");
static FILES: &[FakeFileEntry] = &[
FakeFileEntry {
name: "testfile",
+3 -1
View File
@@ -14,6 +14,7 @@ use crate::arch::x86_64::kmi::{
};
use crate::{
driver::io::{keyboard::*, mouse::MOUSE},
println,
task::scheduler::SCHEDULER,
util::get_bit,
};
@@ -183,13 +184,14 @@ pub fn process_scancode(scancode: u8) -> Option<KeyboardEvent> {
};
if let Some(linux_keycode) = keycode_to_linux(keycode) {
let effective_shift = kbd.get_modifiers().is_shifted() & kbd.get_modifiers().capslock;
return Some(KeyboardEvent {
state: if state == KeyState::Down { 1 } else { 0 },
_pad1: 0,
key: linux_keycode as u16,
mods: 0,
_pad2: 0,
unicode,
unicode: keycode_to_char(linux_keycode, effective_shift).unwrap_or('\0') as u32,
});
} else {
return None;
+2 -5
View File
@@ -196,18 +196,15 @@ pub fn input_interrupt(device_type: &str) {
let event = unsafe { core::ptr::read_volatile(&queue.buffers[desc_idx as usize]) };
handle_event(&event);
let avail_idx = unsafe { core::ptr::read_volatile(&queue.avail.idx) };
queue.avail.ring[(avail_idx as usize) % QUEUE_SIZE] = desc_idx as u16;
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
unsafe {
core::ptr::write_volatile(&mut queue.avail.idx, avail_idx.wrapping_add(1));
}
device.write(VirtioMmioReg::QueueNotify, 0);
handle_event(&event);
}
}
+1 -1
View File
@@ -53,7 +53,7 @@ pub fn get_device(slot: u64) -> Option<VirtioMmio> {
Some(device)
}
pub fn scan_devices() {
pub fn scan_virtio_devices() {
for i in 0..VIRTIO_MMIO_COUNT {
let base = VIRTIO_MMIO_BASE + i * VIRTIO_MMIO_STRIDE;
let device = VirtioMmio::new(base);
+2
View File
@@ -1,4 +1,5 @@
use crate::alloc::string::ToString;
use crate::arch::arch::serial_print;
use crate::driver::graphics::font_render::render_text;
use crate::driver::graphics::framebuffer::Framebuffer;
use crate::{arch::arch::safe_lock, driver::graphics::base::rgb};
@@ -14,6 +15,7 @@ pub struct ConsoleWriter<'a> {
impl Write for ConsoleWriter<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
serial_print(s);
self.console.print(s, self.fb);
Ok(())
}
+42 -42
View File
@@ -2,40 +2,42 @@
#![no_main]
#![cfg_attr(target_arch = "x86_64", feature(abi_x86_interrupt))]
#![feature(naked_functions_rustic_abi)]
extern crate alloc;
use core::fmt::Write;
use core::sync::atomic::{AtomicU64, Ordering};
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::interrupts::enable_interrupts;
use limine::{
BaseRevision,
request::{
DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest,
MemoryMapRequest, RequestsEndMarker, RequestsStartMarker,
},
};
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::paging::AArchPageTable;
#[cfg(target_arch = "aarch64")]
use crate::driver::graphics::primitives::rectangle_filled;
use crate::driver::{graphics::primitives::rectangle_filled, io::virtio::input::init_keyboard};
#[cfg(target_arch = "aarch64")]
use aarch64_cpu::registers::{DAIF, Writeable};
#[cfg(target_arch = "aarch64")]
use crate::driver::io::virtio::input::init_keyboard;
#[cfg(target_arch = "x86_64")]
use crate::driver::elf::loader::run_elf;
#[cfg(target_arch = "x86_64")]
use crate::driver::io::ps2::init_keyboard;
use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_print};
use crate::driver::graphics::base::rgb;
use crate::driver::graphics::framebuffer::{init_framebuffer, with_framebuffer};
use crate::driver::serial::{ConsoleWriter, init_serial_console, with_serial_console};
use crate::driver::timer::TIMER;
use limine::BaseRevision;
use limine::request::{
DateAtBootRequest, ExecutableAddressRequest, FramebufferRequest, HhdmRequest, MemoryMapRequest,
RequestsEndMarker, RequestsStartMarker,
use crate::driver::{
elf::loader::run_elf,
graphics::{
base::rgb,
framebuffer::{init_framebuffer, with_framebuffer},
},
io::fs::assets::INIT_ELF,
serial::{ConsoleWriter, init_serial_console, with_serial_console},
timer::TIMER,
};
pub mod arch;
pub mod config;
pub mod driver;
@@ -43,14 +45,6 @@ pub mod mm;
pub mod task;
pub mod util;
#[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.
/// See specification for further info.
/// Be sure to mark all limine requests with #[used], otherwise they may be removed by the compiler.
@@ -200,13 +194,9 @@ pub unsafe extern "C" fn kernel_main_aarch64(mapper: &mut AArchPageTable) -> ! {
println!("Could not get date at boot. Will default to 0.")
}
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));
});
DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked);
enable_interrupts();
run_elf(INIT_ELF, false, true);
loop {}
}
@@ -217,20 +207,24 @@ pub unsafe fn kernel_main_x86_64() -> ! {
// removed by the linker.
assert!(BASE_REVISION.is_supported());
if let Some(hhdm_response) = HHDM_REQUEST.get_response() {
if let Some(memory_map_response) = MEMORY_MAP_REQUEST.get_response() {
init(hhdm_response, memory_map_response);
let (hhdm_response, memory_map_response) = {
if let Some(a) = HHDM_REQUEST.get_response() {
if let Some(b) = MEMORY_MAP_REQUEST.get_response() {
(a, b)
} else {
kernel_crash(); // Could not get required info from Limine's memory map.
}
} else {
kernel_crash(); // Could not get required info from Limine's memory map.
kernel_crash(); // Could not get required info from Limine's higher-half direct mapping.
}
} else {
kernel_crash(); // Could not get required info from Limine's higher-half direct mapping.
}
};
let mut mapper = init(hhdm_response, memory_map_response);
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
if let Some(limine_framebuffer) = framebuffer_response.framebuffers().next() {
init_framebuffer(&limine_framebuffer);
with_framebuffer(|fb| fb.setup_x86_64());
with_framebuffer(|fb| fb.setup_x86_64(&mut mapper));
} else {
serial_print("no framebuffers found");
}
@@ -246,7 +240,7 @@ pub unsafe fn kernel_main_x86_64() -> ! {
println!("Could not get date at boot. Will default to 0.")
}
run_elf(INIT_ELF_BYTES, false);
run_elf(INIT_ELF, false, true);
loop {}
}
@@ -276,6 +270,12 @@ impl core::fmt::Write for BufWriter<'_> {
#[panic_handler]
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
serial_print("\nKERNEL PANIC:\n");
serial_print(
_info
.message()
.as_str()
.unwrap_or("Could not get message str"),
);
let mut buf = [0u8; 512];
let msg = {
let mut w = BufWriter::new(&mut buf);
+1 -1
View File
@@ -62,7 +62,7 @@ pub struct UserContext {
pub spsr_el1: u64,
pub esr_el1: u64, // exception type
pub far_el1: u64, // fault type
_pad: u64,
pub sp_el0: u64,
}
#[unsafe(no_mangle)]
+20 -42
View File
@@ -4,13 +4,16 @@ use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use crate::{
arch::arch::{enter_usermode, safe_lock},
task::{
context::UserContext,
process::{Process, ProcessState},
},
task::context::UserContext,
task::process::{Process, ProcessState},
util::Locked,
};
#[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::interrupts::run_next;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::syscall::run_next;
pub static CURRENT_PID: AtomicU64 = AtomicU64::new(0);
#[inline]
@@ -119,9 +122,20 @@ impl Locked<Scheduler> {
#[allow(unused_variables, unused_unsafe)]
Some(saved_ctx) => unsafe {
#[cfg(target_arch = "x86_64")]
run_next((&saved_ctx) as *const UserContext, saved_ctx.rsp)
run_next((&saved_ctx) as *const UserContext, saved_ctx.rsp);
#[cfg(target_arch = "aarch64")]
run_next((&saved_ctx) as *const UserContext, saved_ctx.sp_el0);
},
None => enter_usermode(entry as u64, (stack_top & !0xF) - 8, should_swapgs),
None => enter_usermode(
entry as u64,
(stack_top & !0xF)
- cfg_select! {
target_arch = "x86_64" => 8,
target_arch = "aarch64" => 16,
_ => 8
},
should_swapgs,
),
}
}
@@ -136,39 +150,3 @@ impl Locked<Scheduler> {
}
pub static SCHEDULER: Locked<Scheduler> = Locked::new(Scheduler::new());
#[cfg(target_arch = "x86_64")]
#[unsafe(naked)]
#[unsafe(no_mangle)]
unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) {
core::arch::naked_asm!(
"mov gs:[0], rsi", // store new user rsp
"mov rsp, rdi",
"mov r15, qword ptr [rsp + 0]",
"mov r14, qword ptr [rsp + 8]",
"mov r13, qword ptr [rsp + 16]",
"mov r12, qword ptr [rsp + 24]",
"mov r11, qword ptr [rsp + 32]", // rflags
"mov r10, qword ptr [rsp + 40]",
"mov r9, qword ptr [rsp + 48]",
"mov r8, qword ptr [rsp + 56]",
"mov rsi, qword ptr [rsp + 64]",
"mov rdi, qword ptr [rsp + 72]",
"mov rbp, qword ptr [rsp + 80]",
"mov rdx, qword ptr [rsp + 88]",
"mov rcx, qword ptr [rsp + 96]", // rip
"mov rbx, qword ptr [rsp + 104]",
"mov rax, qword ptr [rsp + 112]",
"mov rsp, qword ptr [rsp + 120]", // user rsp
"swapgs",
"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");
}