mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-06-02 12:44:24 +02:00
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:
+4
-1
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Generated
+3
-2
@@ -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"
|
||||||
|
|||||||
@@ -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"] }
|
||||||
|
|||||||
@@ -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())
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]",
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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,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";
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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");
|
||||||
@@ -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,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,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
@@ -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,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,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;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
@@ -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(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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(¤t_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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
Submodule user/apps/doomgeneric updated: 6ce96f770e...c8cde8fe45
+1
-1
Submodule user/init updated: 417af31481...2c1ffa31d6
+1
-1
Submodule user/libxunil updated: e029139d65...a6448bc1f2
Reference in New Issue
Block a user