Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ glob = "0.3.0"
acpi = { git = "https://github.com/rust-osdev/acpi.git", branch = "main" }
hadris-fat = { version = "1.2.0", default-features = false, features = ["alloc", "lfn", "read", "sync"] }
log = "0.4.29"
num_enum = { version = "0.7.6", default-features = false }
pci_types = "0.10.1"
proka-bootloader = "0.5.4"
proka-exec = "0.6.1"
Expand All @@ -24,8 +25,9 @@ x2apic = "0.5.0"
x86_64 = "0.15.5"

[profile.release]
opt-level = 0
opt-level = 3
panic = "abort"
debug = false
codegen-units = 1
incremental = false
incremental = false

89 changes: 80 additions & 9 deletions src/handler/exception.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
//! Exception handler.
//!
//! Originally by moyanj <me@moyanjdc.top>
use crate::memory::IdentityPageTableMapper;
use crate::memory::framealloc::FRAME_ALLOCATOR;
use crate::println;
use crate::process::{DRIVER_PROCESS, NORMAL_PROCESS, ProcType};
use crate::scheduler::{CURRENT_ID, IS_DRIVER};
use core::arch::asm;
use core::sync::atomic::Ordering;
use x86_64::structures::paging::{
FrameAllocator, MappedPageTable, Mapper, Page, PageTable, PageTableFlags, Size4KiB,
};
use x86_64::{
VirtAddr,
registers::control::Cr2,
Expand Down Expand Up @@ -114,10 +120,9 @@ pub extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, err
}

// #PF handler

pub extern "x86-interrupt" fn pagefault(
stack_frame: InterruptStackFrame,
error_code: PageFaultErrorCode,
_stack_frame: InterruptStackFrame,
_error_code: PageFaultErrorCode,
) {
let pml4: u64;
unsafe {
Expand All @@ -135,12 +140,78 @@ pub extern "x86-interrupt" fn pagefault(
Err(_) => VirtAddr::zero(),
};

println!(
"\x1b[31m[ERROR] EXCEPTION: PAGE FAULT in table 0x{:x} at {:#x}\nError Code: {:?}\nFrame: {:#?}\x1b[0m",
pml4, fault_address, error_code, stack_frame
);
// TODO: Exception recovery logic
hlt_loop()
// Time to query the process...
if IS_DRIVER.load(Ordering::Relaxed) {
let binding = DRIVER_PROCESS.read();
let (index, process) = binding
.process
.iter()
.enumerate()
.find(|item| pml4 == item.1.table_addr)
.expect("Process (driver) in the page table is mismatched...");

// Check: is the #PF place in stack range?
if (process.stack_bottom..0x7ffffffff000).contains(&fault_address.as_u64()) {
// We should map the missing place...
let mut mapper = unsafe {
let table_wrapped = &mut *(pml4 as *mut PageTable);
MappedPageTable::new(table_wrapped, IdentityPageTableMapper)
};

// Map 1 4KiB page...
let page = Page::<Size4KiB>::containing_address(fault_address);
let Some(frame) = FRAME_ALLOCATOR.lock().allocate_frame() else {
crate::process::remove(ProcType::Driver, index).unwrap();
hlt_loop()
};
let flags =
PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE;
unsafe {
mapper
.map_to(page, frame, flags, &mut *FRAME_ALLOCATOR.lock())
.expect("Failed to map stack in #PF")
.ignore()
}
}

crate::process::remove(ProcType::Driver, index).unwrap();
hlt_loop()
} else {
let binding = NORMAL_PROCESS.read();
let (index, process) = binding
.process
.iter()
.enumerate()
.find(|item| pml4 == item.1.table_addr || pml4 == item.1.current_table)
.expect("Process (normal) om this page table is mismatched...");

// Check: is #PF in stack range
if (process.stack_bottom..0x7ffffffff000).contains(&fault_address.as_u64()) {
// Create mapper
let mut mapper = unsafe {
let table_wrapped = &mut *(pml4 as *mut PageTable);
MappedPageTable::new(table_wrapped, IdentityPageTableMapper)
};

// Map 1 4KiB page only...
let page = Page::<Size4KiB>::containing_address(fault_address);
let Some(frame) = FRAME_ALLOCATOR.lock().allocate_frame() else {
crate::process::remove(ProcType::Normal, index).unwrap();
hlt_loop()
};
let flags =
PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::NO_EXECUTE;
unsafe {
mapper
.map_to(page, frame, flags, &mut *FRAME_ALLOCATOR.lock())
.expect("Failed to map stack in #PF")
.ignore()
}
}

crate::process::remove(ProcType::Normal, index).unwrap();
hlt_loop()
}
}

// Breakpoint handler
Expand Down
14 changes: 13 additions & 1 deletion src/process/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,30 @@ pub struct DriverProcess {
/// The process context.
pub context: Context,

/// The bottom of the stack.
pub stack_bottom: u64,

/// Current heap bottom.
pub heap_bottom: u64,

/// Current heap top.
pub heap_top: u64,

/// The process's page table.
pub table_addr: u64,
}

impl DriverProcess {
/// Create a process.
#[inline]
pub fn create(frame: u64) -> Result<Self, Error> {
pub fn create(frame: u64, stack_size: u64) -> Result<Self, Error> {
Ok(Self {
present: true,
status: Status::Ready,
context: Context::driver(),
stack_bottom: Context::driver().rsp - stack_size,
heap_top: 0x180000000,
heap_bottom: 0x180000000,
table_addr: frame,
})
}
Expand Down
6 changes: 4 additions & 2 deletions src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,8 @@ pub unsafe fn create(data: &[u8], priority: u8) -> Result<(), Error> {

/// Create a normal process.
fn create_normal(frame: u64, priority: u8) -> Result<(), Error> {
let process = self::normal::NormalProcess::create(frame, priority)?;
// TODO: `proka-exec` support stack size
let process = self::normal::NormalProcess::create(frame, priority, 0x100000)?;

// Check which process is usable
let mut table = NORMAL_PROCESS.write();
Expand All @@ -341,7 +342,8 @@ fn create_normal(frame: u64, priority: u8) -> Result<(), Error> {

/// Create a driver process.
fn create_driver(frame: u64) -> Result<(), Error> {
let process = self::driver::DriverProcess::create(frame)?;
// TODO: `proka-exec` support stack size
let process = self::driver::DriverProcess::create(frame, 0x100000)?;

// Check which process is usable
let mut table = DRIVER_PROCESS.write();
Expand Down
14 changes: 13 additions & 1 deletion src/process/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,32 @@ pub struct NormalProcess {
/// The page table which is currently using.
pub current_table: u64,

/// The stack bottom address.
pub stack_bottom: u64,

/// The heap bottom address.
pub heap_bottom: u64,

/// The heap top address.
pub heap_top: u64,

/// The process's page table.
pub table_addr: u64,
}

impl NormalProcess {
/// Create a process.
#[inline]
pub fn create(frame: u64, priority: u8) -> Result<Self, Error> {
pub fn create(frame: u64, priority: u8, stack_size: u64) -> Result<Self, Error> {
Ok(Self {
present: true,
status: Status::Ready,
priority,
context: Context::normal(),
current_table: frame,
stack_bottom: Context::normal().rsp - stack_size,
heap_top: 0x180000000,
heap_bottom: 0x180000000,
table_addr: frame,
})
}
Expand Down
6 changes: 4 additions & 2 deletions src/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
extern crate alloc;
use crate::process::{Context, DRIVER_PROCESS, NORMAL_PROCESS};
use alloc::vec::Vec;
use core::{mem::offset_of, sync::atomic::{AtomicBool, AtomicUsize, Ordering}};
use core::{
mem::offset_of,
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};
use spin::Mutex;
use x86_64::structures::idt::InterruptStackFrame;

Expand Down Expand Up @@ -249,7 +252,6 @@ pub extern "x86-interrupt" fn switch_task(stack: InterruptStackFrame) {
in("rdi") &context.0,
in("rax") context.1,
);

}
}

Expand Down
Loading