Increase kernel stack size to 2mb, move from cooperative to timer

preemption based scheduling, add correct save_lock on aarch64, add
simple IPC (read, write, manage), and simple and unsecure SHM, add
per-process kernel stacks, add copy_cstr_to_user, always use run_next
for aarch64, remove primitives from the kernel
This commit is contained in:
csd4ni3l
2026-05-26 09:53:59 +02:00
parent 7070b53355
commit 6ebc6ada09
37 changed files with 1065 additions and 475 deletions
+4 -1
View File
@@ -13,6 +13,9 @@ all: $(IMAGE_NAME).iso
.PHONY: run .PHONY: run
run: run-$(KARCH) run: run-$(KARCH)
.PHONY: debug
debug: debug-$(KARCH)
.PHONY: run-x86_64 .PHONY: run-x86_64
run-x86_64: edk2-ovmf $(IMAGE_NAME).iso run-x86_64: edk2-ovmf $(IMAGE_NAME).iso
qemu-system-$(KARCH) \ qemu-system-$(KARCH) \
@@ -64,7 +67,7 @@ debug-aarch64: edk2-ovmf $(IMAGE_NAME).iso
-drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \ -drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(KARCH).fd,readonly=on \
-cdrom $(IMAGE_NAME).iso \ -cdrom $(IMAGE_NAME).iso \
-semihosting-config enable=on,target=native \ -semihosting-config enable=on,target=native \
-d in_asm,int,mmu -dfilter 0xffffffff80000000..0xffffffff80010000 -D /tmp/qemu_trace.log 2>/dev/null \ -d in_asm,int,mmu -D /tmp/qemu_trace.log 2>/dev/null \
$(QEMUFLAGS) $(QEMUFLAGS)
edk2-ovmf: edk2-ovmf:
+1 -1
View File
@@ -1,4 +1,4 @@
export KARCH=x86_64 export KARCH=aarch64
bash build_libxunil.sh bash build_libxunil.sh
bash build_init.sh bash build_init.sh
bash build_doomgeneric.sh bash build_doomgeneric.sh
+2 -2
View File
@@ -1,4 +1,4 @@
export KARCH ?= x86_64 export KARCH ?= aarch64
export OUTPUT ?= kernel export OUTPUT ?= kernel
export MEMORY ?= 4G export MEMORY ?= 1G
export TIMER_FREQUENCY_HZ ?= 1000 export TIMER_FREQUENCY_HZ ?= 1000
+3 -2
View File
@@ -7,6 +7,7 @@ name = "XunilOS"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aarch64-cpu", "aarch64-cpu",
"bitflags",
"fdt", "fdt",
"font8x8", "font8x8",
"heapless", "heapless",
@@ -36,9 +37,9 @@ checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.1" version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
+1
View File
@@ -9,6 +9,7 @@ test = false
bench = false bench = false
[dependencies] [dependencies]
bitflags = "2.11.1"
font8x8 = { version = "0.3.1", default-features = false } font8x8 = { version = "0.3.1", default-features = false }
heapless = "0.9.2" heapless = "0.9.2"
lazy_static = { version = "1.5.0", features = ["spin_no_std"] } lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
+22 -8
View File
@@ -1,18 +1,22 @@
use crate::{ use crate::{
arch::aarch64::{ arch::{
aarch64::{
heap::init_heap, heap::init_heap,
interrupts::init_interrupts, interrupts::init_interrupts,
paging::{AArchPageTable, initialize_paging_aarch64}, paging::{AArchPageTable, initialize_paging_aarch64},
}, },
driver::io::virtio::scan_virtio_devices, arch::KERNEL_MAPPER,
},
driver::{io::virtio::scan_virtio_devices, ipc::init_ipc},
mm::shm::init_shm,
}; };
use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse}; use limine::response::{ExecutableAddressResponse, HhdmResponse, MemoryMapResponse};
// needs to be page aligned since we map it into the page table // needs to be page aligned since we map it into the page table
#[repr(align(4096))] #[repr(align(4096))]
pub struct Stack(pub [u8; 64 * 1024]); pub struct Stack(pub [u8; 2048 * 1024]);
pub static KERNEL_STACK: Stack = Stack([0; 64 * 1024]); pub static KERNEL_STACK: Stack = Stack([0; 2048 * 1024]);
#[unsafe(naked)] #[unsafe(naked)]
pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) { pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) {
@@ -21,10 +25,11 @@ pub unsafe fn init_aarch64_trampoline(mapper: &mut AArchPageTable) {
"msr spsel, #1", "msr spsel, #1",
"adrp x1, {stack}", "adrp x1, {stack}",
"add x1, x1, :lo12:{stack}", "add x1, x1, :lo12:{stack}",
"add sp, x1, {size}", "mov x2, {size}",
"add sp, x1, x2",
"b kernel_main_aarch64", "b kernel_main_aarch64",
stack = sym KERNEL_STACK, stack = sym KERNEL_STACK,
size = const 64 * 1024, size = const 2048usize * 1024,
); );
} }
@@ -33,6 +38,8 @@ pub extern "C" fn init_aarch64(mapper: &mut AArchPageTable) {
init_heap(mapper); init_heap(mapper);
scan_virtio_devices(); scan_virtio_devices();
init_interrupts(); init_interrupts();
init_ipc();
init_shm();
} }
pub fn preinit_aarch64<'a>( pub fn preinit_aarch64<'a>(
@@ -40,10 +47,17 @@ pub fn preinit_aarch64<'a>(
memory_map_response: &'a MemoryMapResponse, memory_map_response: &'a MemoryMapResponse,
executable_address_response: &ExecutableAddressResponse, executable_address_response: &ExecutableAddressResponse,
) { ) {
let mut mapper = initialize_paging_aarch64( let mapper: AArchPageTable = initialize_paging_aarch64(
hhdm_response, hhdm_response,
memory_map_response, memory_map_response,
executable_address_response, executable_address_response,
); );
unsafe { init_aarch64_trampoline(&mut mapper) }; #[allow(static_mut_refs)]
unsafe {
*KERNEL_MAPPER.get_mut() = Some(mapper)
};
#[allow(static_mut_refs)]
unsafe {
init_aarch64_trampoline(KERNEL_MAPPER.get_mut().as_mut().unwrap())
};
} }
+41 -36
View File
@@ -1,15 +1,13 @@
use core::{arch::global_asm, sync::atomic::Ordering}; use core::{arch::global_asm, sync::atomic::Ordering};
use crate::{ use crate::{
arch::syscall::{check_and_reschedule, syscall_dispatch}, arch::{arch::do_interrupt, syscall::syscall_dispatch},
config::TIMER_FREQUENCY_HZ, config::TIMER_FREQUENCY_HZ,
driver::{ driver::io::virtio::{KEYBOARD_SLOT, MOUSE_SLOT, input::input_interrupt},
graphics::framebuffer::with_framebuffer, task::{
io::virtio::{KEYBOARD_SLOT, MOUSE_SLOT, input::input_interrupt}, context::{UserContext, ctx_save},
serial::with_serial_console, scheduler::check_and_reschedule,
timer::TIMER,
}, },
task::context::{UserContext, ctx_save},
}; };
global_asm!( global_asm!(
@@ -54,7 +52,7 @@ macro_rules! exception_handler {
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
unsafe extern "C" fn $name() { unsafe extern "C" fn $name() {
core::arch::naked_asm!( core::arch::naked_asm!(
"sub sp, sp, #288", "sub sp, sp, #304",
"stp x0, x1, [sp, #0]", "stp x0, x1, [sp, #0]",
"stp x2, x3, [sp, #16]", "stp x2, x3, [sp, #16]",
"stp x4, x5, [sp, #32]", "stp x4, x5, [sp, #32]",
@@ -70,8 +68,6 @@ macro_rules! exception_handler {
"stp x24, x25, [sp, #192]", "stp x24, x25, [sp, #192]",
"stp x26, x27, [sp, #208]", "stp x26, x27, [sp, #208]",
"stp x28, x29, [sp, #224]", "stp x28, x29, [sp, #224]",
"mrs x2, sp_el0",
"str x2, [sp, #280]",
"mrs x0, elr_el1", "mrs x0, elr_el1",
"mrs x1, spsr_el1", "mrs x1, spsr_el1",
"stp x30, x0, [sp, #240]", "stp x30, x0, [sp, #240]",
@@ -79,6 +75,10 @@ macro_rules! exception_handler {
"mrs x2, esr_el1", "mrs x2, esr_el1",
"mrs x3, far_el1", "mrs x3, far_el1",
"stp x2, x3, [sp, #264]", "stp x2, x3, [sp, #264]",
"mrs x2, sp_el0",
"str x2, [sp, #280]",
"add x4, sp, #304", // compute stack ptr ourself instead of accessing sp_el1
"str x4, [sp, #288]",
"mov x0, sp", "mov x0, sp",
concat!("bl ", stringify!($rust_handler)), concat!("bl ", stringify!($rust_handler)),
"ldr x2, [sp, #280]", "ldr x2, [sp, #280]",
@@ -102,7 +102,7 @@ macro_rules! exception_handler {
"ldp x24, x25, [sp, #192]", "ldp x24, x25, [sp, #192]",
"ldp x26, x27, [sp, #208]", "ldp x26, x27, [sp, #208]",
"ldp x28, x29, [sp, #224]", "ldp x28, x29, [sp, #224]",
"add sp, sp, #288", "add sp, sp, #304",
"eret" "eret"
); );
} }
@@ -203,42 +203,43 @@ unsafe extern "C" fn irq_handler(ctx: *mut UserContext) {
match interrupt_id { match interrupt_id {
30 => { 30 => {
TIMER.interrupt();
let t = TIMER.interrupt_count.load(Ordering::Relaxed);
if t % 60 == 0 {
with_framebuffer(|fb| {
with_serial_console(|serial_console| serial_console.render(fb));
fb.present();
});
}
let ticks = timer_ticks_per_irq(); let ticks = timer_ticks_per_irq();
unsafe { core::arch::asm!("msr cntp_tval_el0, {}", in(reg) ticks) }; unsafe { core::arch::asm!("msr cntp_tval_el0, {}", in(reg) ticks) };
unsafe { core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64) }; unsafe { core::arch::asm!("msr cntp_ctl_el0, {}", in(reg) 1u64) };
}
interrupt_id if keyboard_irq == interrupt_id as u64 => {
input_interrupt("kbd");
}
interrupt_id if mouse_irq == interrupt_id as u64 => {
input_interrupt("mouse");
}
_ => {}
}
unsafe { unsafe {
gic_eoi(interrupt_id); gic_eoi(interrupt_id);
} }
ctx_save(ctx);
do_interrupt();
check_and_reschedule();
}
interrupt_id if keyboard_irq == interrupt_id as u64 => {
input_interrupt("kbd");
unsafe {
gic_eoi(interrupt_id);
}
}
interrupt_id if mouse_irq == interrupt_id as u64 => {
input_interrupt("mouse");
unsafe {
gic_eoi(interrupt_id);
}
}
_ => unsafe {
gic_eoi(interrupt_id);
},
}
} }
fn handle_aborts(ec: u64, ctx: &UserContext) { fn handle_aborts(ec: u64, ctx: &UserContext) {
match ec { match ec {
ec if ec == 0x25 || ec == 0x24 => { ec if ec == 0x25 || ec == 0x24 => {
panic!( panic!(
"Data abort at VA={:#x} ELR={:#x} ESR={:#x}", "Data abort at VA={:#x} ELR={:#x} ESR={:#x} FAR={:#x}",
ctx.far_el1, ctx.elr_el1, ctx.esr_el1 ctx.far_el1, ctx.elr_el1, ctx.esr_el1, ctx.far_el1
); );
} }
ec if ec == 0x21 || ec == 0x20 => { ec if ec == 0x21 || ec == 0x20 => {
@@ -276,8 +277,6 @@ unsafe extern "C" fn sync_handler_user(ctx: *mut UserContext) {
} as u64; } as u64;
ctx_save(ctx as *const UserContext); ctx_save(ctx as *const UserContext);
let _ = unsafe { check_and_reschedule() };
} }
_ => handle_aborts(ec, ctx), _ => handle_aborts(ec, ctx),
}; };
@@ -296,10 +295,16 @@ pub unsafe fn run_next(ctx: *const UserContext, user_sp: u64) {
core::arch::naked_asm!( core::arch::naked_asm!(
"mov x30, x0", "mov x30, x0",
"msr sp_el0, x1", "msr sp_el0, x1",
"isb",
"ldr x2, [x30, #288]",
"mov sp, x2",
"isb",
"ldr x2, [x30, #248]", "ldr x2, [x30, #248]",
"msr elr_el1, x2", "msr elr_el1, x2",
"isb",
"ldr x3, [x30, #256]", "ldr x3, [x30, #256]",
"msr spsr_el1, x3", "msr spsr_el1, x3",
"isb",
"ldp x0, x1, [x30, #0]", "ldp x0, x1, [x30, #0]",
"ldp x2, x3, [x30, #16]", "ldp x2, x3, [x30, #16]",
"ldp x4, x5, [x30, #32]", "ldp x4, x5, [x30, #32]",
-1
View File
@@ -3,4 +3,3 @@ pub mod heap;
pub mod init; pub mod init;
pub mod interrupts; pub mod interrupts;
pub mod paging; pub mod paging;
pub mod usermode;
+2 -1
View File
@@ -67,6 +67,7 @@ fn phys_to_virt(phys: u64) -> *mut u64 {
pub fn tlb_flush() { pub fn tlb_flush() {
unsafe { unsafe {
core::arch::asm!( core::arch::asm!(
"dsb ishst",
"tlbi vmalle1is", // invalidate TLB "tlbi vmalle1is", // invalidate TLB
"dsb ish", // wait for tlb flush "dsb ish", // wait for tlb flush
"isb", "isb",
@@ -179,7 +180,7 @@ pub fn initialize_paging_aarch64<'a>(
let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base; let stack_phys = KERNEL_STACK.0.as_ptr() as u64 - k_virt_base + k_phys_base;
let stack_virt = KERNEL_STACK.0.as_ptr() as u64; let stack_virt = KERNEL_STACK.0.as_ptr() as u64;
page_table.map_range(stack_virt, stack_phys, 64 * 1024, kernel_data_flags()); page_table.map_range(stack_virt, stack_phys, 2048 * 1024, kernel_data_flags());
set_page_table(page_table.root_phys); set_page_table(page_table.root_phys);
tlb_flush(); tlb_flush();
-15
View File
@@ -1,15 +0,0 @@
#[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)
)
};
}
+30 -34
View File
@@ -5,6 +5,7 @@ pub use crate::arch::x86_64::paging::FRAME_ALLOCATOR_X86_64 as FRAME_ALLOCATOR;
use crate::arch::x86_64::{init::init_x86_64, usermode::enter_usermode_x86_64}; use crate::arch::x86_64::{init::init_x86_64, usermode::enter_usermode_x86_64};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use limine::response::ExecutableAddressResponse; use limine::response::ExecutableAddressResponse;
use spin::mutex::Mutex;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use x86_64::{ use x86_64::{
instructions::interrupts::without_interrupts, instructions::interrupts::without_interrupts,
@@ -17,12 +18,18 @@ use aarch64_cpu::registers::{DAIF, Writeable};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR; pub use crate::arch::aarch64::paging::FRAME_ALLOCATOR_AARCH64 as FRAME_ALLOCATOR;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::{ use crate::arch::aarch64::{init::init_aarch64, paging::AArchPageTable};
init::init_aarch64, paging::AArchPageTable, usermode::enter_usermode_aarch64,
};
use crate::{driver::timer::TIMER, util::align_up}; use crate::{
use core::{arch::asm, sync::atomic::AtomicU64}; config::TIMER_FREQUENCY_HZ,
driver::timer::TIMER,
task::scheduler::{CURRENT_PID, SCHEDULER},
util::align_up,
};
use core::{
arch::asm,
sync::atomic::{AtomicU64, Ordering},
};
use limine::{ use limine::{
memory_map::{Entry, EntryType}, memory_map::{Entry, EntryType},
response::{HhdmResponse, MemoryMapResponse}, response::{HhdmResponse, MemoryMapResponse},
@@ -33,6 +40,14 @@ const UART: *mut u8 = 0x0900_0000 as *mut u8;
pub static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0); pub static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0);
#[cfg(target_arch = "aarch64")]
type PageTable = AArchPageTable;
#[cfg(target_arch = "x86_64")]
type PageTable<'a> = OffsetPageTable<'a>;
pub static mut KERNEL_MAPPER: Mutex<Option<PageTable>> = Mutex::new(None);
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[allow(dead_code)] #[allow(dead_code)]
pub struct UsableRegion { pub struct UsableRegion {
@@ -106,14 +121,12 @@ pub fn init(mapper: &mut AArchPageTable) {
init_aarch64(mapper); init_aarch64(mapper);
} }
#[cfg(target_arch = "x86_64")] pub static GLOBAL_TICK_COUNT: AtomicU64 = AtomicU64::new(0);
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")] #[unsafe(no_mangle)]
pub fn enter_usermode(entry: u64, stack_ptr: u64, should_swapgs: bool) { pub extern "C" fn do_interrupt() {
enter_usermode_aarch64(entry, stack_ptr, should_swapgs); TIMER.interrupt();
GLOBAL_TICK_COUNT.fetch_add(1, Ordering::Relaxed);
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@@ -123,18 +136,12 @@ pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R { pub fn safe_lock<R, F: FnOnce() -> R>(f: F) -> R {
// #[cfg(target_arch = "aarch64")] let old_daif: u64;
// { unsafe { core::arch::asm!("mrs {}, daif", out(reg) old_daif) };
// DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked); core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
// } DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Masked + DAIF::F::Masked);
let r = f(); let r = f();
unsafe { core::arch::asm!("msr daif, {}", in(reg) old_daif) };
// #[cfg(target_arch = "aarch64")]
// {
// DAIF.write(DAIF::D::Masked + DAIF::A::Masked + DAIF::I::Unmasked + DAIF::F::Masked);
// }
r r
} }
@@ -175,17 +182,6 @@ 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();
}
}
pub fn infinite_idle() -> ! { pub fn infinite_idle() -> ! {
loop { loop {
idle() idle()
+251 -57
View File
@@ -1,7 +1,10 @@
#![allow(dead_code, unused_imports)] #![allow(dead_code, unused_imports)]
use core::sync::atomic::Ordering;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::paging::create_and_map_multiple_pages; use crate::arch::x86_64::paging::create_and_map_multiple_pages;
use alloc::vec; use alloc::vec;
use alloc::{string::String, vec::Vec};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use x86_64::{ use x86_64::{
PhysAddr, VirtAddr, PhysAddr, VirtAddr,
@@ -18,7 +21,8 @@ use crate::driver::io::ps2::process_scancodes;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::driver::io::virtio::input::process_keycodes; use crate::driver::io::virtio::input::process_keycodes;
use crate::{ use crate::{
arch::arch::{FRAME_ALLOCATOR, serial_print, sleep}, arch::arch::{FRAME_ALLOCATOR, GLOBAL_TICK_COUNT, serial_print},
config::TIMER_FREQUENCY_HZ,
driver::{ driver::{
elf::loader::run_elf, elf::loader::run_elf,
graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer}, graphics::framebuffer::{FRAMEBUFFER, USER_FB_BASE, with_framebuffer},
@@ -26,9 +30,14 @@ use crate::{
fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read}, fs::vfs::{vfs_close, vfs_lseek, vfs_open, vfs_read},
keyboard::KeyboardEvent, keyboard::KeyboardEvent,
}, },
ipc::{Permissions, create_port, manage_port, read_port, write_port},
timer::TIMER, timer::TIMER,
}, },
print, mm::{
shm::{NEXT_SHM_ID, SHM_REGISTRY, SHM_SLOT_SIZE, SharedMemory, USER_SHM_BASE},
usercopy::copy_cstr_to_user,
},
print, println,
task::{ task::{
process::ProcessState, process::ProcessState,
scheduler::{SCHEDULER, current_pid}, scheduler::{SCHEDULER, current_pid},
@@ -64,6 +73,11 @@ const CLOCK_GETTIME: usize = 228;
const EXIT_GROUP: usize = 231; const EXIT_GROUP: usize = 231;
const KBD_READ: usize = 666; const KBD_READ: usize = 666;
const SLEEP: usize = 909090; // zzz haha const SLEEP: usize = 909090; // zzz haha
const IPC_CREATE: usize = 500;
const IPC_READ: usize = 501;
const IPC_WRITE: usize = 502;
const IPC_MANAGE: usize = 503;
const SHM_OPEN: usize = 600;
pub const MAP_FRAMEBUFFER: usize = 5555; pub const MAP_FRAMEBUFFER: usize = 5555;
pub const FRAMEBUFFER_SWAP: usize = 6666; pub const FRAMEBUFFER_SWAP: usize = 6666;
@@ -224,6 +238,7 @@ fn kbd_read(user_ptr: *mut KeyboardEvent, max_events: isize) -> isize {
to_copy * size_of::<KeyboardEvent>(), to_copy * size_of::<KeyboardEvent>(),
) { ) {
process.kbd_buffer.drain(0..to_copy); process.kbd_buffer.drain(0..to_copy);
return to_copy as isize; return to_copy as isize;
} else { } else {
return -1; return -1;
@@ -367,22 +382,6 @@ pub fn exec(arg0: isize) -> isize {
0 0
} }
pub fn set_reschedule(should_reschedule: bool) {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return;
}
let mut scheduler = SCHEDULER.lock();
if let Some(process) = scheduler.processes.get_mut(&pid) {
process.should_reschedule = should_reschedule;
}
drop(scheduler);
}
pub fn exit() -> isize { pub fn exit() -> isize {
serial_print("Process Exited."); serial_print("Process Exited.");
let pid = current_pid().unwrap_or(0); let pid = current_pid().unwrap_or(0);
@@ -415,31 +414,246 @@ pub fn exit() -> isize {
crate::arch::arch::infinite_idle(); crate::arch::arch::infinite_idle();
} }
#[unsafe(no_mangle)] fn sleep(ticks: isize) -> isize {
pub unsafe extern "C" fn check_and_reschedule() -> usize { let ticks = (ticks as usize) * TIMER_FREQUENCY_HZ / 1000;
let pid = current_pid().unwrap_or(0); let pid = current_pid().unwrap_or(0);
if pid == 0 { if pid == 0 {
return 0; return 0;
} }
let should = SCHEDULER SCHEDULER.with_process(pid, |process| {
.with_process(pid, |process| process.should_reschedule) process.info.wake_tick = Some(TIMER.now().elapsed() + ticks as u64);
.unwrap_or(false); process.state = ProcessState::Blocked;
});
if !should { 0
}
fn ipc_create(name_ptr: isize, default_permissions: isize) -> isize {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0; return 0;
} }
let next_task = SCHEDULER.next_task(); let default_permissions = Permissions::from_bits_retain(default_permissions as u32);
if next_task == pid { let name = match SCHEDULER.with_process(pid, |process| {
let address_space = process.address_space.as_mut().ok_or::<isize>(-1)?;
copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)
}) {
Some(Ok(p)) => p,
_ => return -1,
};
create_port(name, pid, default_permissions);
0
}
fn ipc_read(name_ptr: isize, output_ptr: isize, from: isize) -> isize {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0;
}
let name = match SCHEDULER.with_process(pid, |process| {
let address_space = process.address_space.as_mut().ok_or::<isize>(-1)?;
copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)
}) {
Some(Ok(p)) => p,
_ => return 0,
};
return match read_port(name, pid, from as i64) {
Some(message) => {
let sender = message.from as isize;
SCHEDULER
.with_process(pid, |process| {
process
.address_space
.as_mut()
.map(|address_space| {
copy_cstr_to_user(
&mut address_space.mapper,
message.content,
output_ptr as *mut u8,
)
})
.unwrap_or(Ok(()))
})
.unwrap_or(Ok(()))
.map(|_| sender)
.unwrap_or(0)
}
None => 0,
};
}
fn ipc_write(name_ptr: isize, message_ptr: isize) -> isize {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0; return 0;
} }
SCHEDULER.switch_to(next_task, true); let (name, message) = match SCHEDULER.with_process(pid, |process| {
let address_space = process.address_space.as_mut().ok_or::<isize>(-1)?;
let name = copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)?;
let message =
copy_cstr_from_user(&mut address_space.mapper, message_ptr as *const u8, 256)?;
Ok::<(String, String), isize>((name, message))
}) {
Some(Ok((name, message))) => (name, message),
_ => return -1,
};
1 return match write_port(name, pid, message) {
true => 0,
_ => -1,
};
}
fn ipc_manage(name_ptr: isize, pid_to_set: isize, permissions: isize) -> isize {
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0;
}
let permissions = Permissions::from_bits_retain(permissions as u32);
let name = match SCHEDULER.with_process(pid, |process| {
let address_space = process.address_space.as_mut().ok_or::<isize>(-1)?;
copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)
}) {
Some(Ok(p)) => p,
_ => return -1,
};
return match manage_port(name, pid, pid_to_set as u64, permissions) {
true => 0,
_ => -1,
};
}
fn shm_open(name_ptr: isize, size: isize) -> isize {
if size > (SHM_SLOT_SIZE as f64 * 0.8) as isize {
return -1;
}
let pid = current_pid().unwrap_or(0);
if pid == 0 {
return 0;
}
SCHEDULER
.with_process(pid, |process| -> Result<isize, isize> {
let address_space = process.address_space.as_mut().ok_or::<isize>(-1)?;
let name = copy_cstr_from_user(&mut address_space.mapper, name_ptr as *const u8, 256)?;
#[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(
page,
frame,
PageTableFlags::PRESENT
| PageTableFlags::WRITABLE
| PageTableFlags::USER_ACCESSIBLE
| PageTableFlags::NO_EXECUTE,
&mut *frame_allocator,
)
.unwrap()
.flush();
};
#[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());
};
let size = size as usize;
let mut shm_registry_opt = SHM_REGISTRY.lock();
let shm_registry = shm_registry_opt
.as_mut()
.expect("Could not get SHM registry");
if let Some(shared_memory) = shm_registry.get(&name) {
for (i, page) in shared_memory.phys_pages.iter().enumerate() {
map_page(
USER_SHM_BASE + shared_memory.id * SHM_SLOT_SIZE + i as u64 * 4096,
*page,
);
}
#[cfg(target_arch = "aarch64")]
crate::arch::aarch64::paging::tlb_flush();
Ok(shared_memory.id as isize)
} else {
let mut page_count = align_up(size as u64, 4096) / 4096;
if size as u64 % 4096 == 0 {
// Map one extra page to tolerate end-boundary reads.
page_count += 1;
}
let mut phys_pages = Vec::new();
#[cfg(target_arch = "aarch64")]
for _ in 0..page_count {
use crate::arch::aarch64::paging::alloc_frame;
phys_pages.push(alloc_frame().expect("Could not allocate frame"));
}
#[cfg(target_arch = "x86_64")]
for _ in 0..page_count {
let mut frame_allocator = FRAME_ALLOCATOR.lock();
phys_pages.push(
frame_allocator
.allocate_frame()
.expect("Could not allocate frame")
.start_address()
.as_u64(),
);
}
let id = NEXT_SHM_ID.fetch_add(1, Ordering::Relaxed);
shm_registry.insert(name.clone(), SharedMemory { id, phys_pages });
let shared_memory = shm_registry.get(&name.clone()).ok_or::<isize>(-1)?;
for (i, page) in shared_memory.phys_pages.iter().enumerate() {
map_page(
USER_SHM_BASE + shared_memory.id * SHM_SLOT_SIZE + i as u64 * 4096,
*page,
);
}
#[cfg(target_arch = "aarch64")]
crate::arch::aarch64::paging::tlb_flush();
Ok(shared_memory.id as isize)
}
})
.unwrap_or(Err(-1))
.unwrap_or(-1)
} }
#[allow(unused_variables)] #[allow(unused_variables)]
@@ -453,27 +667,6 @@ pub unsafe extern "C" fn syscall_dispatch(
arg4: isize, arg4: isize,
arg5: isize, arg5: isize,
) -> isize { ) -> isize {
#[cfg(target_arch = "x86_64")]
interrupts::enable();
set_reschedule(match num {
BRK => false,
READ => false,
WRITE => false,
OPEN => true,
CLOSE => true,
LSEEK => false,
EXIT => true,
SLEEP => true,
CLOCK_GETTIME => false,
MAP_FRAMEBUFFER => false,
KBD_READ => false,
FRAMEBUFFER_SWAP => false,
GETPID => false,
EXECVE => true,
_ => false,
});
match num { match num {
BRK => unsafe { sbrk(arg0) }, BRK => unsafe { sbrk(arg0) },
READ => read(arg0, arg1, arg2, arg3) as isize, READ => read(arg0, arg1, arg2, arg3) as isize,
@@ -498,12 +691,9 @@ pub unsafe extern "C" fn syscall_dispatch(
CLOSE => close(arg0), CLOSE => close(arg0),
LSEEK => vfs_lseek(arg0 as i64, arg1 as i64, arg2 as i32) as isize, LSEEK => vfs_lseek(arg0 as i64, arg1 as i64, arg2 as i32) as isize,
EXIT => exit(), EXIT => exit(),
SLEEP => { SLEEP => sleep(arg0),
sleep(arg0 as u64);
0
}
EXECVE => exec(arg0), EXECVE => exec(arg0),
CLOCK_GETTIME => TIMER.now().elapsed() as isize, CLOCK_GETTIME => ((TIMER.now().elapsed() as usize) * (TIMER_FREQUENCY_HZ / 1000)) as isize,
MAP_FRAMEBUFFER => map_framebuffer(), MAP_FRAMEBUFFER => map_framebuffer(),
KBD_READ => kbd_read(arg0 as *mut KeyboardEvent, arg1), KBD_READ => kbd_read(arg0 as *mut KeyboardEvent, arg1),
GETPID => { GETPID => {
@@ -514,12 +704,16 @@ pub unsafe extern "C" fn syscall_dispatch(
_ => return pid as isize, _ => return pid as isize,
} }
} }
IPC_CREATE => ipc_create(arg0, arg1),
IPC_READ => ipc_read(arg0, arg1, arg2),
IPC_WRITE => ipc_write(arg0, arg1),
IPC_MANAGE => ipc_manage(arg0, arg1, arg2),
SHM_OPEN => shm_open(arg0, arg1),
FRAMEBUFFER_SWAP => { FRAMEBUFFER_SWAP => {
with_framebuffer(|fb| { with_framebuffer(|fb| fb.present());
fb.present();
});
0 0
} }
_ => -38, // syscall not found _ => -38, // syscall not found
} }
} }
+36 -21
View File
@@ -1,4 +1,8 @@
use core::mem::MaybeUninit;
use alloc::boxed::Box;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use spin::mutex::Mutex;
use x86_64::VirtAddr; use x86_64::VirtAddr;
use x86_64::instructions::segmentation::{CS, DS, ES, SS, Segment}; use x86_64::instructions::segmentation::{CS, DS, ES, SS, Segment};
use x86_64::instructions::tables::load_tss; use x86_64::instructions::tables::load_tss;
@@ -6,31 +10,35 @@ use x86_64::structures::{
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector}, gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
tss::TaskStateSegment, tss::TaskStateSegment,
}; };
pub const TIMER_IST_INDEX: u16 = 1;
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0; pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
lazy_static! { pub static TSS_MUTEX: Mutex<Option<&'static mut TaskStateSegment>> = Mutex::new(None);
#[repr(C, align(4096))]
pub static ref TSS: TaskStateSegment = {
let mut tss = TaskStateSegment::new();
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = {
const STACK_SIZE: usize = 4096 * 5;
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let stack_start = VirtAddr::from_ptr(&raw const STACK); #[allow(static_mut_refs)]
let stack_end = stack_start + STACK_SIZE as u64; fn make_tss() -> &'static mut TaskStateSegment {
stack_end static mut TSS_STORAGE: MaybeUninit<TaskStateSegment> = MaybeUninit::uninit();
};
tss.privilege_stack_table[0] = { unsafe {
const STACK_SIZE: usize = 4096 * 5; let tss_ptr = TSS_STORAGE.as_mut_ptr();
static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; tss_ptr.write(TaskStateSegment::new());
let tss: &mut TaskStateSegment = &mut *tss_ptr;
const STACK_SIZE: usize = 4096 * 5;
static mut DOUBLE_FAULT_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let df_start = VirtAddr::from_ptr(&DOUBLE_FAULT_STACK as *const _);
tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX as usize] = df_start + STACK_SIZE as u64;
static mut PRIVILEGE_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let p_start = VirtAddr::from_ptr(&PRIVILEGE_STACK as *const _);
tss.privilege_stack_table[0] = p_start + STACK_SIZE as u64;
static mut TIMER_IST_STACK: [u8; STACK_SIZE] = [0; STACK_SIZE];
let ti_start = VirtAddr::from_ptr(&TIMER_IST_STACK as *const _);
tss.interrupt_stack_table[TIMER_IST_INDEX as usize] = ti_start + STACK_SIZE as u64;
let stack_start = VirtAddr::from_ptr(&raw const STACK);
let stack_end = stack_start + STACK_SIZE as u64;
stack_end
};
tss tss
}; }
} }
lazy_static! { lazy_static! {
@@ -45,6 +53,10 @@ lazy_static! {
SegmentSelector SegmentSelector
) )
) = { ) = {
let tss: &'static mut TaskStateSegment = make_tss();
let tss_ptr: *mut TaskStateSegment = tss as *mut _;
*TSS_MUTEX.lock() = Some(tss);
let mut gdt = GlobalDescriptorTable::new(); let mut gdt = GlobalDescriptorTable::new();
let kernel_code_selector = gdt.append(Descriptor::kernel_code_segment()); let kernel_code_selector = gdt.append(Descriptor::kernel_code_segment());
let kernel_data_selector = gdt.append(Descriptor::kernel_data_segment()); let kernel_data_selector = gdt.append(Descriptor::kernel_data_segment());
@@ -59,7 +71,10 @@ lazy_static! {
let user_data_selector = gdt.append(Descriptor::user_data_segment()); let user_data_selector = gdt.append(Descriptor::user_data_segment());
let user_code_selector = gdt.append(Descriptor::user_code_segment()); let user_code_selector = gdt.append(Descriptor::user_code_segment());
let tss_selector = gdt.append(Descriptor::tss_segment(&TSS));
let tss_ref: &'static TaskStateSegment = unsafe { &*tss_ptr };
let tss_selector = gdt.append(Descriptor::tss_segment(tss_ref));
( (
gdt, gdt,
( (
+12 -4
View File
@@ -1,5 +1,7 @@
use crate::{ use crate::{
arch::x86_64::{ arch::{
arch::serial_print,
x86_64::{
gdt::load_gdt_x86_64, gdt::load_gdt_x86_64,
heap::init_heap, heap::init_heap,
interrupts::{PICS, init_idt_x86_64}, interrupts::{PICS, init_idt_x86_64},
@@ -7,8 +9,10 @@ use crate::{
paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64}, paging::{FRAME_ALLOCATOR_X86_64, initialize_paging_x86_64},
syscall::init_syscalls, syscall::init_syscalls,
}, },
},
config::TIMER_FREQUENCY_HZ, config::TIMER_FREQUENCY_HZ,
driver::io::mouse::MOUSE, driver::{io::mouse::MOUSE, ipc::init_ipc},
mm::shm::init_shm,
}; };
use x86_64::{ use x86_64::{
@@ -79,9 +83,8 @@ pub fn init_x86_64<'a>(
} }
let kmi_status = setup_kmi(); let kmi_status = setup_kmi();
set_pit_interval();
interrupts::enable(); set_pit_interval();
let mut mapper = memory_management_init(hhdm_response, memory_map_response); let mut mapper = memory_management_init(hhdm_response, memory_map_response);
@@ -89,7 +92,12 @@ pub fn init_x86_64<'a>(
.ok() .ok()
.expect("Failed to initalize heap"); .expect("Failed to initalize heap");
interrupts::enable();
MOUSE.set_status(kmi_status); MOUSE.set_status(kmi_status);
init_ipc();
init_shm();
return mapper; return mapper;
} }
+111 -11
View File
@@ -1,4 +1,4 @@
use core::sync::atomic::Ordering; use core::{arch::naked_asm, sync::atomic::Ordering};
use crate::{ use crate::{
arch::{arch::serial_print, x86_64::gdt}, arch::{arch::serial_print, x86_64::gdt},
@@ -15,6 +15,7 @@ use lazy_static::lazy_static;
use pic8259::ChainedPics; use pic8259::ChainedPics;
use spin::Mutex; use spin::Mutex;
use x86_64::{ use x86_64::{
VirtAddr,
registers::control::Cr2, registers::control::Cr2,
structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}, structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
}; };
@@ -50,8 +51,10 @@ lazy_static! {
idt.double_fault idt.double_fault
.set_handler_fn(double_fault_handler) .set_handler_fn(double_fault_handler)
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
idt[InterruptIndex::Timer.as_u8()]
.set_handler_addr(VirtAddr::new(timer_interrupt_handler as *const u8 as u64))
.set_stack_index(gdt::TIMER_IST_INDEX);
} }
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
idt.page_fault.set_handler_fn(page_fault_handler); idt.page_fault.set_handler_fn(page_fault_handler);
idt.general_protection_fault.set_handler_fn(gpf_handler); idt.general_protection_fault.set_handler_fn(gpf_handler);
idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler); idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler);
@@ -99,17 +102,114 @@ pub extern "x86-interrupt" fn invalid_opcode_handler(stack_frame: InterruptStack
panic!("EXCEPTION: INVALID OPCODE\n{:#?}", stack_frame); panic!("EXCEPTION: INVALID OPCODE\n{:#?}", stack_frame);
} }
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { #[unsafe(naked)]
TIMER.interrupt(); pub fn timer_interrupt_handler() {
naked_asm!(
r#"
test qword ptr [rsp + 8], 3
jz .from_kernel
let t = TIMER.interrupt_count.load(Ordering::Relaxed); swapgs
if t % 60 == 0 {
with_framebuffer(|fb| {
with_serial_console(|serial_console| serial_console.render(fb));
fb.present();
});
}
sub rsp, 144
mov [rsp + 0], r15
mov [rsp + 8], r14
mov [rsp + 16], r13
mov [rsp + 24], r12
mov [rsp + 32], r11
mov [rsp + 40], r10
mov [rsp + 48], r9
mov [rsp + 56], r8
mov [rsp + 64], rsi
mov [rsp + 72], rdi
mov [rsp + 80], rbp
mov [rsp + 88], rdx
mov [rsp + 96], rcx
mov [rsp + 104], rbx
mov [rsp + 112], rax
mov rax, [rsp + 144 + 0]
mov [rsp + 128], rax
mov rax, [rsp + 144 + 16]
mov [rsp + 136], rax
mov rax, [rsp + 144 + 24]
mov [rsp + 120], rax
mov rdi, rsp
call ctx_save
call do_interrupt
call eoi
call check_and_reschedule
test rax, rax
jnz .switched
mov rax, [rsp + 112]
mov rbx, [rsp + 104]
mov rcx, [rsp + 96]
mov rdx, [rsp + 88]
mov rbp, [rsp + 80]
mov rdi, [rsp + 72]
mov rsi, [rsp + 64]
mov r8, [rsp + 56]
mov r9, [rsp + 48]
mov r10, [rsp + 40]
mov r11, [rsp + 32]
mov r12, [rsp + 24]
mov r13, [rsp + 16]
mov r14, [rsp + 8]
mov r15, [rsp + 0]
add rsp, 144
swapgs
iretq
.from_kernel:
push rbp
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rdi
push rsi
push rdx
push rcx
push rbx
push rax
call do_interrupt
call eoi
pop rax
pop rbx
pop rcx
pop rdx
pop rsi
pop rdi
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
pop rbp
iretq
.switched:
ud2
"#
)
}
#[unsafe(no_mangle)]
extern "C" fn eoi() {
unsafe { unsafe {
PICS.lock() PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8()); .notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
+50 -38
View File
@@ -3,7 +3,7 @@ use core::arch::asm;
use x86_64::instructions::tlb::flush_all; use x86_64::instructions::tlb::flush_all;
use crate::{ use crate::{
arch::x86_64::gdt::{GDT, TSS}, arch::x86_64::gdt::{GDT, TSS_MUTEX},
task::context::UserContext, task::context::UserContext,
}; };
@@ -21,7 +21,7 @@ pub struct PerCpuData {
pub kernel_rsp: u64, pub kernel_rsp: u64,
} }
static mut PER_CPU: PerCpuData = PerCpuData { pub static mut PER_CPU: PerCpuData = PerCpuData {
user_rsp: 0, user_rsp: 0,
kernel_rsp: 0, kernel_rsp: 0,
}; };
@@ -65,8 +65,9 @@ pub fn init_syscalls() {
asm!("mov gs, ax", in("ax") 0u16); asm!("mov gs, ax", in("ax") 0u16);
let kernel_stack_top = TSS.privilege_stack_table[0].as_u64(); if let Some(tss) = TSS_MUTEX.lock().as_ref() {
PER_CPU.kernel_rsp = kernel_stack_top; PER_CPU.kernel_rsp = tss.privilege_stack_table[0].as_u64();
}
#[allow(function_casts_as_integer)] #[allow(function_casts_as_integer)]
wrmsr(IA32_LSTAR, syscall_entry as u64); // set syscall entry function wrmsr(IA32_LSTAR, syscall_entry as u64); // set syscall entry function
@@ -94,7 +95,7 @@ unsafe extern "C" fn syscall_entry() {
mov gs:[0], rsp mov gs:[0], rsp
mov rsp, gs:[8] mov rsp, gs:[8]
sub rsp, 128 sub rsp, 144
mov qword ptr [rsp + 0], r15 mov qword ptr [rsp + 0], r15
mov qword ptr [rsp + 8], r14 mov qword ptr [rsp + 8], r14
@@ -115,6 +116,11 @@ unsafe extern "C" fn syscall_entry() {
mov rax, qword ptr gs:[0] mov rax, qword ptr gs:[0]
mov qword ptr [rsp + 120], rax mov qword ptr [rsp + 120], rax
mov rax, qword ptr [rsp + 96]
mov qword ptr [rsp + 128], rax
mov rax, qword ptr [rsp + 32]
mov qword ptr [rsp + 136], rax
mov rbx, rsp // rbx = frame base mov rbx, rsp // rbx = frame base
// ctx_save(frame) // ctx_save(frame)
@@ -123,7 +129,6 @@ unsafe extern "C" fn syscall_entry() {
call ctx_save call ctx_save
mov rsp, rbx mov rsp, rbx
// syscall_dispatch(num,arg0..arg5)
mov rdi, qword ptr [rbx + 112] mov rdi, qword ptr [rbx + 112]
mov rsi, qword ptr [rbx + 72] mov rsi, qword ptr [rbx + 72]
mov rdx, qword ptr [rbx + 64] mov rdx, qword ptr [rbx + 64]
@@ -131,28 +136,23 @@ unsafe extern "C" fn syscall_entry() {
mov r8, qword ptr [rbx + 40] mov r8, qword ptr [rbx + 40]
mov r9, qword ptr [rbx + 56] mov r9, qword ptr [rbx + 56]
lea rsp, [rbx - 24] // rsp%16==8 before call lea rsp, [rbx - 24]
mov rax, qword ptr [rbx + 48] mov rax, qword ptr [rbx + 48]
mov qword ptr [rsp + 0], rax mov qword ptr [rsp + 0], rax
call syscall_dispatch call syscall_dispatch
mov rsp, rbx mov rsp, rbx
// save return value into frame (so normal restore uses it)
mov qword ptr [rbx + 112], rax mov qword ptr [rbx + 112], rax
// ctx_save(frame) again so saved_ctx.rax reflects return value
mov rdi, rbx mov rdi, rbx
lea rsp, [rbx - 8] lea rsp, [rbx - 8]
call ctx_save call ctx_save
mov rsp, rbx mov rsp, rbx
// maybe switch tasks (this should not return if it switches) mov rax, qword ptr [rsp + 128]
lea rsp, [rbx - 8] mov qword ptr [rsp + 96], rax
call check_and_reschedule mov rax, qword ptr [rsp + 136]
mov rsp, rbx mov qword ptr [rsp + 32], rax
test rax, rax
jnz .done
// restore registers from frame // restore registers from frame
mov rax, qword ptr [rsp + 112] mov rax, qword ptr [rsp + 112]
@@ -165,12 +165,11 @@ unsafe extern "C" fn syscall_entry() {
mov r8, qword ptr [rsp + 56] mov r8, qword ptr [rsp + 56]
mov r9, qword ptr [rsp + 48] mov r9, qword ptr [rsp + 48]
mov r10, qword ptr [rsp + 40] mov r10, qword ptr [rsp + 40]
mov r11, qword ptr [rsp + 32] // rflags — sysretq loads RFLAGS from r11 mov r11, qword ptr [rsp + 32]
mov r12, qword ptr [rsp + 24] mov r12, qword ptr [rsp + 24]
mov r13, qword ptr [rsp + 16] mov r13, qword ptr [rsp + 16]
mov r14, qword ptr [rsp + 8] mov r14, qword ptr [rsp + 8]
mov r15, qword ptr [rsp + 0] mov r15, qword ptr [rsp + 0]
// don't restore rsp from frame — use the user rsp we saved in gs:[0]
mov rsp, qword ptr gs:[0] mov rsp, qword ptr gs:[0]
swapgs swapgs
sysretq sysretq
@@ -182,27 +181,40 @@ unsafe extern "C" fn syscall_entry() {
#[unsafe(naked)] #[unsafe(naked)]
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub unsafe fn run_next(ctx: *const UserContext, user_rsp: u64) { pub unsafe fn run_next(ctx: *const UserContext, user_rsp: u64, user_cs: u64, user_ss: u64) {
core::arch::naked_asm!( core::arch::naked_asm!(
"mov gs:[0], rsi", // store new user rsp // rdi = ctx, rsi = user_rsp, rdx = user_cs, rcx = user_ss
"mov rsp, rdi", "mov gs:[0], rsi",
"mov r15, qword ptr [rsp + 0]", "mov rax, rcx",
"mov r14, qword ptr [rsp + 8]", "and eax, 0xFFFC",
"mov r13, qword ptr [rsp + 16]", "mov ds, ax",
"mov r12, qword ptr [rsp + 24]", "mov es, ax",
"mov r11, qword ptr [rsp + 32]", // rflags // save ctx ptr on stack, then build iret frame
"mov r10, qword ptr [rsp + 40]", "push rdi",
"mov r9, qword ptr [rsp + 48]", "push rcx",
"mov r8, qword ptr [rsp + 56]", "push rsi",
"mov rsi, qword ptr [rsp + 64]", "push qword ptr [rdi + 136]",
"mov rdi, qword ptr [rsp + 72]", "push rdx",
"mov rbp, qword ptr [rsp + 80]", "push qword ptr [rdi + 128]",
"mov rdx, qword ptr [rsp + 88]", // load all gp regs via rdi
"mov rcx, qword ptr [rsp + 96]", // rip "mov r15, qword ptr [rdi + 0]",
"mov rbx, qword ptr [rsp + 104]", "mov r14, qword ptr [rdi + 8]",
"mov rax, qword ptr [rsp + 112]", "mov r13, qword ptr [rdi + 16]",
"mov rsp, qword ptr [rsp + 120]", // user rsp "mov r12, qword ptr [rdi + 24]",
"mov r11, qword ptr [rdi + 32]",
"mov r10, qword ptr [rdi + 40]",
"mov r9, qword ptr [rdi + 48]",
"mov r8, qword ptr [rdi + 56]",
"mov rsi, qword ptr [rdi + 64]",
"mov rbp, qword ptr [rdi + 80]",
"mov rdx, qword ptr [rdi + 88]",
"mov rcx, qword ptr [rdi + 96]",
// ctx_ptr is at [rsp + 40]
"mov rax, qword ptr [rsp + 40]",
"mov rbx, qword ptr [rax + 104]",
"mov rdi, qword ptr [rax + 72]",
"mov rax, qword ptr [rax + 112]",
"swapgs", "swapgs",
"sysretq", "iretq",
); );
} }
+1 -1
View File
@@ -1,2 +1,2 @@
pub const TIMER_FREQUENCY_HZ: usize = 1000; pub const TIMER_FREQUENCY_HZ: usize = 1000;
pub const KARCH: &str = "x86_64"; pub const KARCH: &str = "aarch64";
+142 -6
View File
@@ -1,7 +1,10 @@
use core::ptr::null; use core::{
ptr::null,
sync::atomic::{AtomicU64, Ordering},
};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::paging::create_and_map_multiple_pages; use crate::arch::x86_64::{interrupts, paging::create_and_map_multiple_pages};
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::driver::elf::{ use crate::driver::elf::{
header::{ header::{
@@ -13,11 +16,19 @@ use crate::driver::elf::{
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::paging::{ use crate::arch::aarch64::paging::{
AArchPageTable, create_and_map_multiple_pages, user_data_flags, AArchPageTable, create_and_map_multiple_pages, kernel_data_flags, user_data_flags,
};
use crate::{
arch::arch::KERNEL_MAPPER,
mm::address_space::AddressSpace,
println,
task::{context::UserContext, scheduler::SCHEDULER},
}; };
use crate::{mm::address_space::AddressSpace, println, task::scheduler::SCHEDULER};
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use x86_64::structures::paging::{OffsetPageTable, PageTableFlags}; use x86_64::{
registers::control::{Cr3, Cr3Flags},
structures::paging::{OffsetPageTable, PageTableFlags, PhysFrame, Size4KiB},
};
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
type PageTable = AArchPageTable; type PageTable = AArchPageTable;
@@ -25,6 +36,29 @@ type PageTable = AArchPageTable;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
type PageTable<'a> = OffsetPageTable<'a>; type PageTable<'a> = OffsetPageTable<'a>;
static mut NEXT_KERNEL_STACK_ADDR: AtomicU64 = AtomicU64::new(0xFFFF_FFFF_7000_0000);
pub fn next_kstack(mapper: &mut PageTable) -> u64 {
const PAGES: u64 = 2048;
#[allow(static_mut_refs)]
let addr = unsafe { NEXT_KERNEL_STACK_ADDR.fetch_add(PAGES * 4096, Ordering::Relaxed) };
#[cfg(target_arch = "aarch64")]
create_and_map_multiple_pages(mapper, PAGES, addr, kernel_data_flags());
#[cfg(target_arch = "x86_64")]
create_and_map_multiple_pages(
mapper,
PAGES,
addr,
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
);
assert!(addr & 0xF == 0, "kernel stack isn't 16 byte aligned");
addr + PAGES * 4096
}
pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool { pub fn validate_elf(elf_header: &Elf64Ehdr, elf_len: usize) -> bool {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
let required_machine = EM_X86_64; let required_machine = EM_X86_64;
@@ -73,20 +107,54 @@ pub fn load_file(mapper: &mut PageTable, elf_bytes: &[u8]) -> (*const u8, u64) {
} }
pub fn run_elf(file_bytes: &[u8], should_swapgs: bool, switch_to: bool) { pub fn run_elf(file_bytes: &[u8], should_swapgs: bool, switch_to: bool) {
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("msr daifset, #2")
};
#[cfg(target_arch = "x86_64")]
{
use x86_64::instructions::interrupts;
interrupts::disable();
}
let stack_base: u64 = 0x0000_7fff_0000_0000; let stack_base: u64 = 0x0000_7fff_0000_0000;
let page_count = 4096; // 16 mib let page_count = 4096; // 16 mib
let page_size = 0x1000u64; let page_size = 0x1000u64;
let stack_top = stack_base + (page_count as u64 * page_size); let stack_top = stack_base + (page_count as u64 * page_size);
if let Some(mut address_space) = AddressSpace::new() { if let Some(mut address_space) = AddressSpace::new() {
#[cfg(target_arch = "aarch64")]
let previous_pt_ptr: u64;
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("mrs {}, ttbr0_el1", out(reg) previous_pt_ptr)
};
#[cfg(target_arch = "x86_64")]
let previous_pt: (PhysFrame<Size4KiB>, Cr3Flags);
#[cfg(target_arch = "x86_64")]
{
use x86_64::registers::control::Cr3;
previous_pt = Cr3::read();
}
address_space.use_address_space(); address_space.use_address_space();
let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes); let (entry_point, heap_base) = load_file(&mut address_space.mapper, file_bytes);
println!("Entry point: {:?}", entry_point); println!("Entry point: {:?}", entry_point);
#[allow(static_mut_refs)]
let process_pid = SCHEDULER let process_pid = SCHEDULER
.spawn_process(entry_point as u64, stack_top, heap_base) .spawn_process(
entry_point as u64,
stack_top,
next_kstack(unsafe { KERNEL_MAPPER.get_mut().as_mut().unwrap() }),
heap_base,
)
.unwrap(); .unwrap();
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@@ -109,8 +177,76 @@ pub fn run_elf(file_bytes: &[u8], should_swapgs: bool, switch_to: bool) {
process.address_space = Some(address_space) process.address_space = Some(address_space)
}); });
#[cfg(target_arch = "aarch64")]
SCHEDULER.with_process(process_pid, |process| {
process.saved_ctx = Some(UserContext {
x0: 0,
x1: 0,
x2: 0,
x3: 0,
x4: 0,
x5: 0,
x6: 0,
x7: 0,
x8: 0,
x9: 0,
x10: 0,
x11: 0,
x12: 0,
x13: 0,
x14: 0,
x15: 0,
x16: 0,
x17: 0,
x18: 0,
x19: 0,
x20: 0,
x21: 0,
x22: 0,
x23: 0,
x24: 0,
x25: 0,
x26: 0,
x27: 0,
x28: 0,
x29: 0,
x30: 0,
elr_el1: entry_point as u64,
spsr_el1: 0,
esr_el1: 0,
far_el1: 0,
sp_el0: process.stack_top,
sp_el1: process.kernel_stack_top,
_pad1: 0,
});
});
if switch_to { if switch_to {
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("msr daifset, #2")
};
SCHEDULER.switch_to(process_pid, should_swapgs); SCHEDULER.switch_to(process_pid, should_swapgs);
} else {
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!(
"msr ttbr0_el1, {root}",
"dsb ishst",
"tlbi vmalle1is",
"dsb ish",
"isb",
root = in(reg) previous_pt_ptr
);
}
#[cfg(target_arch = "x86_64")]
unsafe {
use x86_64::instructions::interrupts;
Cr3::write(previous_pt.0, previous_pt.1);
interrupts::enable();
};
} }
} else { } else {
return; return;
-3
View File
@@ -1,3 +0,0 @@
pub fn rgb(r: u8, g: u8, b: u8) -> u32 {
((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}
+13 -1
View File
@@ -1,9 +1,21 @@
extern crate font8x8; extern crate font8x8;
use crate::driver::graphics::framebuffer::Framebuffer; use crate::driver::graphics::framebuffer::Framebuffer;
use crate::driver::graphics::primitives::rectangle_filled;
use font8x8::legacy::BASIC_LEGACY; use font8x8::legacy::BASIC_LEGACY;
pub fn rectangle_filled(
framebuffer: &mut Framebuffer,
x: usize,
y: usize,
width: usize,
height: usize,
color: u32,
) {
for yy in y..y + height {
framebuffer.fill_span(x, yy, width, color);
}
}
pub fn render_char( pub fn render_char(
framebuffer: &mut Framebuffer, framebuffer: &mut Framebuffer,
start_x: usize, start_x: usize,
+4 -2
View File
@@ -1,4 +1,6 @@
pub mod base;
pub mod font_render; pub mod font_render;
pub mod framebuffer; pub mod framebuffer;
pub mod primitives;
pub fn rgb(r: u8, g: u8, b: u8) -> u32 {
((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}
-178
View File
@@ -1,178 +0,0 @@
use crate::driver::graphics::framebuffer::Framebuffer;
pub fn line(framebuffer: &mut Framebuffer, x0: usize, y0: usize, x1: usize, y1: usize, color: u32) {
if y0 == y1 {
let (xa, xb) = if x0 <= x1 { (x0, x1) } else { (x1, x0) };
framebuffer.fill_span(xa, y0, xb - xa + 1, color);
return;
}
if x0 == x1 {
let (ya, yb) = if y0 <= y1 { (y0, y1) } else { (y1, y0) };
for yy in ya..=yb {
framebuffer.put_pixel(x0, yy, color);
}
return;
}
let mut x0 = x0 as isize;
let mut y0 = y0 as isize;
let x1 = x1 as isize;
let y1 = y1 as isize;
let mut dx: isize = x1 - x0;
let mut dy: isize = y1 - y0;
if dx < 0 {
dx = -dx;
}
if dy < 0 {
dy = -dy;
}
let step_x: isize = if x0 < x1 { 1 } else { -1 };
let step_y: isize = if y0 < y1 { 1 } else { -1 };
let mut error: isize = dx - dy;
loop {
framebuffer.put_pixel(x0 as usize, y0 as usize, color);
let e2: isize = 2 * error;
if e2 > -dy {
error -= dy;
x0 += step_x;
}
if e2 < dx {
error += dx;
y0 += step_y;
}
if x0 == x1 && y0 == y1 {
break;
}
}
}
pub fn triangle_outline(
framebuffer: &mut Framebuffer,
x1: usize,
y1: usize,
x2: usize,
y2: usize,
x3: usize,
y3: usize,
color: u32,
) {
line(framebuffer, x1, y1, x2, y2, color);
line(framebuffer, x1, y1, x3, y3, color);
line(framebuffer, x2, y2, x3, y3, color);
}
pub fn circle_outline(
framebuffer: &mut Framebuffer,
cx: usize,
cy: usize,
radius: usize,
color: u32,
) {
let mut x = radius as isize;
let mut y: isize = 0;
let mut d = 1 - x;
let cx = cx as isize;
let cy = cy as isize;
#[inline(always)]
fn plot_points(
framebuffer: &mut Framebuffer,
cx: isize,
cy: isize,
x: isize,
y: isize,
color: u32,
) {
framebuffer.put_pixel((cx + x) as usize, (cy + y) as usize, color);
framebuffer.put_pixel((cx + y) as usize, (cy + x) as usize, color);
framebuffer.put_pixel((cx - y) as usize, (cy + x) as usize, color);
framebuffer.put_pixel((cx - x) as usize, (cy + y) as usize, color);
framebuffer.put_pixel((cx - x) as usize, (cy - y) as usize, color);
framebuffer.put_pixel((cx - y) as usize, (cy - x) as usize, color);
framebuffer.put_pixel((cx + y) as usize, (cy - x) as usize, color);
framebuffer.put_pixel((cx + x) as usize, (cy - y) as usize, color);
}
while y <= x {
plot_points(framebuffer, cx, cy, x, y, color);
y += 1;
if d <= 0 {
d += 2 * y + 1;
} else {
x -= 1;
d += 2 * (y - x) + 1;
}
}
}
pub fn circle_filled(
framebuffer: &mut Framebuffer,
x0: usize,
y0: usize,
radius: usize,
color: u32,
) {
let mut x = radius as isize;
let mut y: isize = 0;
let mut x_change: isize = 1 - (radius as isize * 2);
let mut y_change: isize = 0;
let mut radius_error: isize = 0;
while x >= y {
let mut i = x0 as isize - x;
while i <= x0 as isize + x {
framebuffer.put_pixel(i as usize, (y0 as isize + y) as usize, color);
framebuffer.put_pixel(i as usize, (y0 as isize - y) as usize, color);
i += 1;
}
let mut i = x0 as isize - y;
while i <= x0 as isize + y {
framebuffer.put_pixel(i as usize, (y0 as isize + x) as usize, color);
framebuffer.put_pixel(i as usize, (y0 as isize - x) as usize, color);
i += 1;
}
y += 1;
radius_error += y_change;
y_change += 2;
if (radius_error * 2) + x_change > 0 {
x -= 1;
radius_error += x_change;
x_change += 2;
}
}
}
pub fn rectangle_filled(
framebuffer: &mut Framebuffer,
x: usize,
y: usize,
width: usize,
height: usize,
color: u32,
) {
for yy in y..y + height {
framebuffer.fill_span(x, yy, width, color);
}
}
pub fn rectangle_outline(
framebuffer: &mut Framebuffer,
x: usize,
y: usize,
width: usize,
height: usize,
color: u32,
) {
line(framebuffer, x, y, x + width, y, color); // bottomleft -> bottomright
line(framebuffer, x, y + height, x + width, y + height, color); // topleft -> topright
line(framebuffer, x, y, x, y + height, color); // bottomleft -> topleft
line(framebuffer, x + width, y, x + width, y + height, color); // bottomright -> topright
}
+4 -4
View File
@@ -1,5 +1,5 @@
pub static INIT_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/init"); pub static INIT_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/init");
pub static DOOM_WAD: &[u8] = include_bytes!("../../../../../assets/doom1.wad"); pub static DOOM_WAD: &[u8] = include_bytes!("../../../../../assets/doom1.wad");
pub static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/doomgeneric"); pub static DOOM_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/doomgeneric");
pub static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/helloworld.elf"); pub static HELLOWORLD_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/helloworld.elf");
pub static BADAPPLE_ELF: &[u8] = include_bytes!("../../../../../assets/x86_64/badapple"); pub static BADAPPLE_ELF: &[u8] = include_bytes!("../../../../../assets/aarch64/badapple");
+143
View File
@@ -0,0 +1,143 @@
use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
use bitflags::bitflags;
use spin::Mutex;
use crate::arch::arch::safe_lock;
type PID = u64;
bitflags! {
#[derive(Debug)]
pub struct Permissions: u32 {
const READ = 1 << 0;
const WRITE = 1 << 1;
const MANAGE = 1 << 2;
}
}
#[derive(Clone)]
pub struct Message {
pub from: PID,
pub content: String,
}
pub struct Port {
pub messages: Vec<Message>,
pub permissions: BTreeMap<PID, Permissions>,
pub default_permissions: Permissions,
}
pub static PORTS: Mutex<Option<BTreeMap<String, Port>>> = Mutex::new(None);
pub fn init_ipc() {
*PORTS.lock() = Some(BTreeMap::new());
}
pub fn create_port(name: String, pid: u64, default_permissions: Permissions) {
let mut permissions = BTreeMap::new();
permissions.insert(
pid as PID,
Permissions::READ | Permissions::WRITE | Permissions::MANAGE,
);
safe_lock(|| {
PORTS.lock().as_mut().expect("IPC not initialized").insert(
name,
Port {
messages: Vec::new(),
permissions,
default_permissions,
},
);
});
}
pub fn read_port(name: String, pid: u64, from: i64) -> Option<Message> {
safe_lock(|| {
let mut guard = PORTS.lock();
let ports = guard.as_mut().expect("IPC not initialized");
if let Some(port) = ports.get_mut(&name) {
let permissions = port
.permissions
.get(&pid)
.unwrap_or(&port.default_permissions);
if !permissions.contains(Permissions::READ) {
return None;
}
if from != -1 {
if let Some(index) = port
.messages
.iter()
.position(|message| message.from == from as u64)
{
return Some(port.messages.remove(index));
}
None
} else {
if let Some(index) = port
.messages
.iter()
.position(|message| message.from != pid as u64)
{
return Some(port.messages.remove(index));
}
None
}
} else {
None
}
})
}
pub fn write_port(name: String, pid: u64, message: String) -> bool {
return safe_lock(|| {
let mut guard = PORTS.lock();
let ports = guard.as_mut().expect("IPC not initialized");
if let Some(port) = ports.get_mut(&name) {
let permissions = port
.permissions
.get(&pid)
.unwrap_or(&port.default_permissions);
if permissions.contains(Permissions::WRITE) {
port.messages.push(Message {
from: pid,
content: message,
});
return true;
} else {
return false;
}
} else {
return false;
}
});
}
pub fn manage_port(name: String, pid: u64, pid_to_set: u64, new_permissions: Permissions) -> bool {
return safe_lock(|| {
let mut guard = PORTS.lock();
let ports = guard.as_mut().expect("IPC not initialized");
if let Some(port) = ports.get_mut(&name) {
let permissions = port
.permissions
.get(&pid)
.unwrap_or(&port.default_permissions);
if permissions.contains(Permissions::MANAGE) {
port.permissions.insert(pid_to_set, new_permissions);
return true;
} else {
return false;
}
} else {
return false;
}
});
}
+1
View File
@@ -1,5 +1,6 @@
pub mod elf; pub mod elf;
pub mod graphics; pub mod graphics;
pub mod io; pub mod io;
pub mod ipc;
pub mod serial; pub mod serial;
pub mod timer; pub mod timer;
+2 -1
View File
@@ -2,7 +2,7 @@ use crate::alloc::string::ToString;
use crate::arch::arch::serial_print; use crate::arch::arch::serial_print;
use crate::driver::graphics::font_render::render_text; use crate::driver::graphics::font_render::render_text;
use crate::driver::graphics::framebuffer::Framebuffer; use crate::driver::graphics::framebuffer::Framebuffer;
use crate::{arch::arch::safe_lock, driver::graphics::base::rgb}; use crate::{arch::arch::safe_lock, driver::graphics::rgb};
use alloc::string::String; use alloc::string::String;
use core::fmt::{self, Write}; use core::fmt::{self, Write};
use spin::Mutex; use spin::Mutex;
@@ -15,6 +15,7 @@ pub struct ConsoleWriter<'a> {
impl Write for ConsoleWriter<'_> { impl Write for ConsoleWriter<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result { fn write_str(&mut self, s: &str) -> fmt::Result {
serial_print(s);
self.console.print(s, self.fb); self.console.print(s, self.fb);
Ok(()) Ok(())
} }
+11 -2
View File
@@ -18,8 +18,12 @@ use limine::{
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::paging::AArchPageTable; use crate::arch::aarch64::paging::AArchPageTable;
#[cfg(target_arch = "x86_64")]
use crate::arch::arch::KERNEL_MAPPER;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::driver::{graphics::primitives::rectangle_filled, io::virtio::input::init_keyboard}; use crate::driver::io::virtio::input::init_keyboard;
#[cfg(target_arch = "aarch64")]
use crate::util::U64Buf;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use aarch64_cpu::registers::{DAIF, Writeable}; use aarch64_cpu::registers::{DAIF, Writeable};
@@ -30,8 +34,8 @@ use crate::arch::arch::{HHDM_OFFSET, infinite_idle, init, kernel_crash, serial_p
use crate::driver::{ use crate::driver::{
elf::loader::run_elf, elf::loader::run_elf,
graphics::{ graphics::{
base::rgb,
framebuffer::{init_framebuffer, with_framebuffer}, framebuffer::{init_framebuffer, with_framebuffer},
rgb,
}, },
io::fs::assets::INIT_ELF, io::fs::assets::INIT_ELF,
serial::{ConsoleWriter, init_serial_console, with_serial_console}, serial::{ConsoleWriter, init_serial_console, with_serial_console},
@@ -234,6 +238,11 @@ pub unsafe fn kernel_main_x86_64() -> ! {
init_keyboard(); init_keyboard();
#[allow(static_mut_refs)]
unsafe {
*KERNEL_MAPPER.get_mut() = Some(mapper)
};
if let Some(date_at_boot_response) = DATE_AT_BOOT_REQUEST.get_response() { if let Some(date_at_boot_response) = DATE_AT_BOOT_REQUEST.get_response() {
TIMER.set_date_at_boot(date_at_boot_response.timestamp().as_secs()); TIMER.set_date_at_boot(date_at_boot_response.timestamp().as_secs());
} else { } else {
+8 -6
View File
@@ -8,7 +8,7 @@ use x86_64::{
}; };
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::paging::{AArchPageTable, tlb_flush}; use crate::arch::aarch64::paging::AArchPageTable;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET}; use crate::arch::arch::{FRAME_ALLOCATOR, HHDM_OFFSET};
@@ -90,11 +90,13 @@ impl AddressSpace {
core::arch::asm!( core::arch::asm!(
"msr ttbr0_el1, {root}", "msr ttbr0_el1, {root}",
"isb", "isb",
root = in(reg) self.ttbr0_phys "dsb ishst",
); "tlbi vmalle1is",
} "dsb ish",
"isb",
tlb_flush(); root = in(reg) self.mapper.root_phys
)
};
} }
} }
+1
View File
@@ -1,3 +1,4 @@
pub mod address_space; pub mod address_space;
pub mod heap; pub mod heap;
pub mod shm;
pub mod usercopy; pub mod usercopy;
+18
View File
@@ -0,0 +1,18 @@
use core::sync::atomic::AtomicU64;
use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
use spin::mutex::Mutex;
pub const USER_SHM_BASE: u64 = 0x0000_7000_0000_0000;
pub static SHM_REGISTRY: Mutex<Option<BTreeMap<String, SharedMemory>>> = Mutex::new(None);
pub static NEXT_SHM_ID: AtomicU64 = AtomicU64::new(1);
pub const SHM_SLOT_SIZE: u64 = 64 * 1024 * 1024;
pub struct SharedMemory {
pub id: u64,
pub phys_pages: Vec<u64>,
}
pub fn init_shm() {
*SHM_REGISTRY.lock() = Some(BTreeMap::new());
}
+16 -1
View File
@@ -1,4 +1,5 @@
use alloc::{ use alloc::{
ffi::CString,
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
@@ -128,7 +129,7 @@ pub fn copy_cstr_from_user(
return Err(-14); return Err(-14);
} }
let mut buf: Vec<u8> = Vec::with_capacity(64); let mut buf: Vec<u8> = Vec::with_capacity(max_len);
for i in 0..max_len { for i in 0..max_len {
let mut byte = 0u8; let mut byte = 0u8;
@@ -143,3 +144,17 @@ pub fn copy_cstr_from_user(
Err(-36) Err(-36)
} }
pub fn copy_cstr_to_user(
mapper: &mut PageTable,
kernel_str: String,
user_ptr: *mut u8,
) -> Result<(), isize> {
if user_ptr.is_null() {
return Err(-14);
}
let c_string = CString::new(kernel_str).map_err(|_| -14isize)?;
let len = c_string.count_bytes();
let _ = copy_to_user(mapper, user_ptr, c_string.into_raw() as *const u8, len);
Ok(())
}
+9 -5
View File
@@ -4,12 +4,11 @@ use crate::task::scheduler::{SCHEDULER, current_pid};
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct UserContext { pub struct UserContext {
//general purpose data regs
pub r15: u64, pub r15: u64,
pub r14: u64, pub r14: u64,
pub r13: u64, pub r13: u64,
pub r12: u64, pub r12: u64,
pub r11: u64, // rflags pub r11: u64,
pub r10: u64, pub r10: u64,
pub r9: u64, pub r9: u64,
pub r8: u64, pub r8: u64,
@@ -17,10 +16,12 @@ pub struct UserContext {
pub rdi: u64, pub rdi: u64,
pub rbp: u64, pub rbp: u64,
pub rdx: u64, pub rdx: u64,
pub rcx: u64, // rip pub rcx: u64,
pub rbx: u64, pub rbx: u64,
pub rax: u64, pub rax: u64,
pub rsp: u64, // user rsp pub rsp: u64,
pub rip: u64,
pub rflags: u64,
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@@ -63,6 +64,8 @@ pub struct UserContext {
pub esr_el1: u64, // exception type pub esr_el1: u64, // exception type
pub far_el1: u64, // fault type pub far_el1: u64, // fault type
pub sp_el0: u64, pub sp_el0: u64,
pub sp_el1: u64,
pub _pad1: u64,
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@@ -70,7 +73,8 @@ pub extern "C" fn ctx_save(regs: *const UserContext) {
if let Some(pid) = current_pid() { if let Some(pid) = current_pid() {
let mut guard = SCHEDULER.lock(); let mut guard = SCHEDULER.lock();
if let Some(process) = guard.processes.get_mut(&pid) { if let Some(process) = guard.processes.get_mut(&pid) {
let saved_ctx = unsafe { core::ptr::read(regs) }; let saved_ctx = unsafe { core::ptr::read_unaligned(regs) };
process.saved_ctx = Some(saved_ctx); process.saved_ctx = Some(saved_ctx);
} }
} }
+9 -4
View File
@@ -1,8 +1,10 @@
use core::sync::atomic::Ordering;
use alloc::vec::Vec; use alloc::vec::Vec;
use crate::{ use crate::{
driver::io::keyboard::KeyboardEvent, mm::address_space::AddressSpace, arch::arch::GLOBAL_TICK_COUNT, driver::io::keyboard::KeyboardEvent,
task::context::UserContext, mm::address_space::AddressSpace, task::context::UserContext,
}; };
pub enum ProcessState { pub enum ProcessState {
@@ -22,13 +24,14 @@ pub struct Process {
pub pid: u64, pub pid: u64,
pub state: ProcessState, pub state: ProcessState,
pub stack_top: u64, pub stack_top: u64,
pub kernel_stack_top: u64,
pub heap_base: u64, pub heap_base: u64,
pub heap_end: u64, pub heap_end: u64,
pub kbd_buffer: Vec<KeyboardEvent>, pub kbd_buffer: Vec<KeyboardEvent>,
pub address_space: Option<AddressSpace>, pub address_space: Option<AddressSpace>,
pub saved_ctx: Option<UserContext>, pub saved_ctx: Option<UserContext>,
pub should_reschedule: bool,
pub user_entry: u64, pub user_entry: u64,
pub last_switch_tick: u64,
pub info: ProcessInfo, pub info: ProcessInfo,
} }
impl Process { impl Process {
@@ -36,19 +39,21 @@ impl Process {
pid: u64, pid: u64,
user_entry: u64, user_entry: u64,
stack_top: u64, stack_top: u64,
kernel_stack_top: u64,
heap_base: u64, heap_base: u64,
heap_end: u64, heap_end: u64,
) -> Process { ) -> Process {
Process { Process {
pid, pid,
stack_top, stack_top,
kernel_stack_top,
state: ProcessState::Ready, state: ProcessState::Ready,
heap_base, heap_base,
heap_end, heap_end,
last_switch_tick: GLOBAL_TICK_COUNT.load(Ordering::Relaxed),
kbd_buffer: Vec::new(), kbd_buffer: Vec::new(),
address_space: None, address_space: None,
saved_ctx: None, saved_ctx: None,
should_reschedule: false,
user_entry, user_entry,
info: ProcessInfo { info: ProcessInfo {
exit_code: 0, exit_code: 0,
+109 -21
View File
@@ -3,16 +3,31 @@ use core::sync::atomic::{AtomicU64, Ordering};
use alloc::{collections::btree_map::BTreeMap, vec::Vec}; use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use crate::{ use crate::{
arch::arch::{enter_usermode, safe_lock}, arch::arch::{GLOBAL_TICK_COUNT, safe_lock},
task::context::UserContext, config::TIMER_FREQUENCY_HZ,
task::process::{Process, ProcessState}, driver::timer::TIMER,
task::{
context::UserContext,
process::{Process, ProcessState},
},
util::Locked, util::Locked,
}; };
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use crate::arch::aarch64::interrupts::run_next; use crate::arch::aarch64::interrupts::run_next;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::syscall::run_next; use crate::arch::x86_64::{
gdt::{user_code_selector, user_data_selector},
syscall::run_next,
usermode::enter_usermode_x86_64,
};
#[cfg(target_arch = "x86_64")]
use x86_64::structures::gdt::SegmentSelector;
#[cfg(target_arch = "x86_64")]
fn with_rpl3(ss: SegmentSelector) -> u64 {
(ss.0 as u64) | 3
}
pub static CURRENT_PID: AtomicU64 = AtomicU64::new(0); pub static CURRENT_PID: AtomicU64 = AtomicU64::new(0);
@@ -44,11 +59,24 @@ impl Scheduler {
} }
impl Locked<Scheduler> { impl Locked<Scheduler> {
pub fn spawn_process(&self, entry_point: u64, stack_top: u64, heap_base: u64) -> Option<u64> { pub fn spawn_process(
&self,
entry_point: u64,
stack_top: u64,
kernel_stack_top: u64,
heap_base: u64,
) -> Option<u64> {
let mut guard = safe_lock(|| self.lock()); let mut guard = safe_lock(|| self.lock());
let pid = guard.next_pid; let pid = guard.next_pid;
guard.next_pid += 1; guard.next_pid += 1;
let process = Process::new(pid, entry_point, stack_top, heap_base, heap_base); let process = Process::new(
pid,
entry_point,
stack_top,
kernel_stack_top,
heap_base,
heap_base,
);
guard.processes.insert(pid, process); guard.processes.insert(pid, process);
Some(pid) Some(pid)
@@ -58,6 +86,15 @@ impl Locked<Scheduler> {
if let Some(previous_pid) = current_pid() { if let Some(previous_pid) = current_pid() {
let mut guard = safe_lock(|| self.lock()); let mut guard = safe_lock(|| self.lock());
for process in guard.processes.values_mut() {
if process.info.wake_tick.is_some() {
if TIMER.now().elapsed() >= process.info.wake_tick.unwrap() {
process.state = ProcessState::Ready;
process.info.wake_tick = None;
}
}
}
if let Some(process) = guard.processes.get_mut(&previous_pid) { if let Some(process) = guard.processes.get_mut(&previous_pid) {
if matches!(process.state, ProcessState::Running) { if matches!(process.state, ProcessState::Running) {
process.state = ProcessState::Ready; process.state = ProcessState::Ready;
@@ -89,8 +126,9 @@ impl Locked<Scheduler> {
}; };
} }
#[allow(unused_variables)]
pub fn switch_to(&self, pid: u64, should_swapgs: bool) { pub fn switch_to(&self, pid: u64, should_swapgs: bool) {
let (ctx_opt, entry, stack_top) = { let (ctx_opt, entry, stack_top, kernel_stack_top) = {
let mut guard = safe_lock(|| self.lock()); let mut guard = safe_lock(|| self.lock());
if let Some(previous_pid) = current_pid() { if let Some(previous_pid) = current_pid() {
@@ -113,29 +151,45 @@ impl Locked<Scheduler> {
new_process.saved_ctx, new_process.saved_ctx,
new_process.user_entry, new_process.user_entry,
new_process.stack_top, new_process.stack_top,
new_process.kernel_stack_top,
) )
}; };
set_current_pid(Some(pid)); set_current_pid(Some(pid));
match ctx_opt {
#[allow(unused_variables, unused_unsafe)]
Some(saved_ctx) => unsafe {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
run_next((&saved_ctx) as *const UserContext, saved_ctx.rsp); unsafe {
use x86_64::VirtAddr;
use crate::arch::x86_64::{gdt::TSS_MUTEX, syscall::PER_CPU};
PER_CPU.kernel_rsp = kernel_stack_top;
if let Some(tss) = TSS_MUTEX.lock().as_mut() {
tss.privilege_stack_table[0] = VirtAddr::new(kernel_stack_top);
}
}
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
unsafe {
let saved_ctx = ctx_opt.expect("Could not get user context");
run_next((&saved_ctx) as *const UserContext, saved_ctx.sp_el0); run_next((&saved_ctx) as *const UserContext, saved_ctx.sp_el0);
}
#[cfg(target_arch = "x86_64")]
match ctx_opt {
Some(saved_ctx) => unsafe {
let user_cs = with_rpl3(user_code_selector());
let user_ss = with_rpl3(user_data_selector());
run_next(
(&saved_ctx) as *const UserContext,
saved_ctx.rsp,
user_cs,
user_ss,
);
}, },
None => enter_usermode( None => {
entry as u64, enter_usermode_x86_64(entry as u64, (stack_top & !0xF) - 8, should_swapgs);
(stack_top & !0xF) }
- cfg_select! {
target_arch = "x86_64" => 8,
target_arch = "aarch64" => 16,
_ => 8
},
should_swapgs,
),
} }
} }
@@ -150,3 +204,37 @@ impl Locked<Scheduler> {
} }
pub static SCHEDULER: Locked<Scheduler> = Locked::new(Scheduler::new()); pub static SCHEDULER: Locked<Scheduler> = Locked::new(Scheduler::new());
#[unsafe(no_mangle)]
pub extern "C" fn check_and_reschedule() -> isize {
let current_pid = CURRENT_PID.load(Ordering::Relaxed);
let should = safe_lock(|| {
let mut scheduler = SCHEDULER.lock();
if let Some(process) = scheduler.processes.get_mut(&current_pid) {
let elapsed = GLOBAL_TICK_COUNT.load(Ordering::Relaxed) - process.last_switch_tick;
if elapsed >= (TIMER_FREQUENCY_HZ / 60) as u64 {
process.last_switch_tick = GLOBAL_TICK_COUNT.load(Ordering::Relaxed);
true
} else {
false
}
} else {
false
}
});
if should {
let next_task = SCHEDULER.next_task();
if next_task == current_pid {
return 0;
}
SCHEDULER.switch_to(next_task, true);
1
} else {
0
}
}