Repository navigation
API_Usage
This guide provides detailed documentation for the kernel's public APIs. It covers the main modules, their interfaces, and how to use them correctly.
- Core APIs
- Memory Management APIs
- Task Management APIs
- VFS APIs
- System Call APIs
- Error Handling APIs
- Common Patterns
Initializes the global kernel instance.
use crate::error::KernelResult;
pub fn init_kernel() -> KernelResult<()>Usage:
if let Err(e) = init_kernel() {
panic!("Failed to initialize kernel: {}", e);
}Notes:
- Must be called once during early boot
- Panics if called multiple times
- Initializes scheduler and idle task
Returns a mutable reference to the global kernel instance.
pub fn kernel() -> &'static mut KernelUsage:
let kernel = kernel();
let pmm = kernel.pmm();
let scheduler = kernel.scheduler_mut();Safety:
- Only safe to call after
init_kernel() - Returns a static mutable reference
Checks if the kernel has been initialized.
pub fn is_initialized() -> boolUsage:
if !is_initialized() {
init_kernel().expect("Kernel initialization failed");
}Manages physical page allocation.
pub struct PhysicalMemoryManager {
// Internal state
}
impl PhysicalMemoryManager {
pub fn new() -> Self;
/// Allocates a physical page
pub fn alloc(&mut self) -> KernelResult<PhysicalAddress>;
/// Frees a physical page
pub fn free(&mut self, addr: PhysicalAddress) -> KernelResult<()>
/// Gets available memory statistics
pub fn stats(&self) -> MemoryStats;
}Usage:
let pmm = kernel().pmm_mut();
let page = pmm.alloc()?;
// Use page
pmm.free(page)?;Initializes the memory subsystem.
pub fn init_memory(multiboot_info: usize, allocator: &PmmAllocator) -> KernelResult<()>Usage:
memory::init::init_memory(multiboot_info, &ALLOCATOR)?;Manages virtual memory mappings.
pub struct VirtualMemoryManager {
// Internal state
}
impl VirtualMemoryManager {
pub fn new() -> Self;
/// Maps a virtual address to physical address
pub fn map(&mut self, virt: VirtualAddress, phys: PhysicalAddress) -> KernelResult<()>
/// Unmaps a virtual address
pub fn unmap(&mut self, virt: VirtualAddress) -> KernelResult<()>
/// Handles page faults
pub fn handle_page_fault(&mut self, addr: VirtualAddress) -> KernelResult<()>
}Usage:
let vmm = kernel().vmm_mut().unwrap();
vmm.map(virt_addr, phys_addr)?;Represents a task (process/thread).
pub struct Task {
pub id: TaskId,
pub state: TaskState,
pub stack: PhysicalAddress,
pub entry_point: VirtualAddress,
pub name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskState {
New,
Ready,
Running,
Blocked,
Zombie,
}Usage:
let task = Task {
id: TaskId::new(),
state: TaskState::Ready,
stack: stack_addr,
entry_point: entry_addr,
name: "my_task".to_string(),
};Manages task scheduling.
pub struct Scheduler {
// Internal state
}
impl Scheduler {
pub fn new() -> Self;
/// Initializes the scheduler
pub fn init(&mut self);
/// Spawns a new task
pub fn spawn(&mut self, func: fn(), name: &str) -> KernelResult<TaskId>;
/// Runs the scheduler (main loop)
pub fn run(&mut self) -> !;
/// Yields the current task
pub fn yield_task(&mut self);
/// Gets current task
pub fn current_task(&self) -> Option<&Task>>;
}Usage:
let scheduler = kernel().scheduler_mut();
scheduler.spawn(my_function, "my_task")?;
scheduler.run(); // Never returnsConvenience function to spawn a task.
pub fn spawn(func: fn(), name: &str) -> KernelResult<TaskId>Usage:
task::spawn(my_function, "my_task")?;The main interface for file system objects.
pub trait Inode {
fn read(&self, offset: u64, buffer: &mut [u8]) -> KernelResult<usize>;
fn write(&self, offset: u64, buffer: &[u8]) -> KernelResult<usize>;
fn read_dir(&self, offset: u64) -> KernelResult<Option<DirEntry>>;
fn create(&self, name: &str, mode: FileMode) -> KernelResult<InodeId>>;
fn remove(&self, name: &str) -> KernelResult<()>
fn get_attr(&self) -> KernelResult<FileAttr>>;
fn set_attr(&self, attr: &FileAttr) -> KernelResult<()>
}Usage:
let inode = get_inode(path)?;
let mut buffer = [0u8; 512];
inode.read(0, &mut buffer)?;Represents an open file.
pub struct File {
inode: InodeId,
offset: u64,
flags: OpenFlags,
}
impl File {
pub fn read(&mut self, buffer: &mut [u8]) -> KernelResult<usize>;
pub fn write(&mut self, buffer: &[u8]) -> KernelResult<usize>;
pub fn seek(&mut self, pos: u64) -> KernelResult<()>
pub fn close(&mut self) -> KernelResult<()>
pub fn get_attr(&self) -> KernelResult<FileAttr>>;
}Usage:
let mut file = File::open(path, OpenFlags::RDWR)?;
let mut buffer = [0u8; 1024];
let bytes_read = file.read(&mut buffer)?;Manages mount points.
pub struct MountNamespace {
// Internal state
}
impl MountNamespace {
pub fn new() -> Self;
/// Mounts a filesystem
pub fn mount(&mut self, source: &str, target: &str, fstype: &str, flags: u32) -> KernelResult<()>
/// Unmounts a filesystem
pub fn unmount(&mut self, target: &str, flags: u32) -> KernelResult<()>
/// Gets mount information
pub fn get_mount(&self, path: &str) -> Option<&Mount>>;
}Usage:
let mut mount_ns = MountNamespace::new();
mount_ns.mount("tmpfs", "/tmp", "tmpfs", 0)?;Enum of available system calls.
#[repr(u32)]
pub enum SyscallNumber {
Exit = 1,
Write = 4,
Read = 3,
Open = 5,
Close = 6,
GetPid = 20,
GetPpid = 39,
Fork = 57,
Execve = 59,
GetUid = 24,
GetGid = 47,
SetUid = 23,
SetGid = 46,
}Handles system calls from user mode.
pub fn handle_syscall(num: u32, args: &[usize; 6]) -> SyscallResultUsage:
// Called from interrupt handler
let result = handle_syscall(syscall_num, &args);Terminates the current task.
pub fn sys_exit(status: i32) -> !;Writes to a file descriptor.
pub fn sys_write(fd: u32, buf: *const u8, count: usize) -> isize;Reads from a file descriptor.
pub fn sys_read(fd: u32, buf: *mut u8, count: usize) -> isize;Opens a file.
pub fn sys_open(path: *const u8, flags: u32) -> u32;The unified error type for the kernel.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KernelError {
// Memory errors
OutOfMemory,
InvalidAddress,
PageFault,
// VFS errors
NotFound,
PermissionDenied,
Exists,
// Task errors
TaskNotFound,
TaskAlreadyRunning,
InvalidTaskState,
// System call errors
InvalidSyscall,
SyscallNotImplemented,
InvalidArgument,
// Initialization errors
InitFailed(&'static str),
DriverFailed(&'static str),
// Architecture errors
TssInitFailed,
GdtInitFailed,
IdtInitFailed,
// Generic errors
NotImplemented,
InvalidState,
Unknown,
}Result type alias for kernel operations.
pub type KernelResult<T> = Result<T, KernelError>;Usage:
fn read_file(path: &str) -> KernelResult<Vec<u8>> {
if path.is_empty() {
return Err(KernelError::InvalidArgument);
}
// Implementation
Ok(data)
}Use the ? operator for error propagation:
fn complex_operation() -> KernelResult<()>
{
let pmm = kernel().pmm_mut();
let page = pmm.alloc()?;
let vmm = kernel().vmm_mut().unwrap();
vmm.map(virt_addr, page)?;
Ok(())
}Use RAII patterns for resource management:
struct FileHandle {
file: File,
}
impl Drop for FileHandle {
fn drop(&mut self) {
self.file.close().unwrap_or_else(|e| {
serial::write_string(&format!("Failed to close file: {}\n", e));
});
}
}Use the initialization pattern for modules:
pub mod my_module {
use crate::error::KernelResult;
static INIT: spin::Once<KernelResult<()>> = spin::Once::new();
pub fn init() -> KernelResult<()>
{
INIT.call_once(|| {
// Initialization code
Ok(())
})
}
pub fn is_initialized() -> bool {
INIT.is_completed()
}
}Use spin locks for thread-safe access:
use spin::Mutex;
static COUNTER: Mutex<u32> = Mutex::new(0);
pub fn increment_counter() {
let mut counter = COUNTER.lock();
*counter += 1;
}-
Always handle errors - Never ignore
KernelResult -
Use RAII - Implement
Dropfor resource cleanup -
Document unsafe code - Use
// SAFETY:comments - Prefer safe abstractions - Use safe Rust when possible
- Check initialization - Verify modules are initialized before use
- Use appropriate lifetimes - Avoid unnecessary static references
- Validate inputs - Never trust external data
This API guide covers the most commonly used interfaces. For more detailed documentation, refer to the source code comments and module documentation.