Skip to content

API_Usage

Zikithezikit edited this page Mar 2, 2026 · 1 revision

API Usage Guide

This guide provides detailed documentation for the kernel's public APIs. It covers the main modules, their interfaces, and how to use them correctly.

Table of Contents

  1. Core APIs
  2. Memory Management APIs
  3. Task Management APIs
  4. VFS APIs
  5. System Call APIs
  6. Error Handling APIs
  7. Common Patterns

Core APIs

Kernel State Management

kernel::init_kernel()

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

kernel::kernel()

Returns a mutable reference to the global kernel instance.

pub fn kernel() -> &'static mut Kernel

Usage:

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

kernel::is_initialized()

Checks if the kernel has been initialized.

pub fn is_initialized() -> bool

Usage:

if !is_initialized() {
    init_kernel().expect("Kernel initialization failed");
}

Memory Management APIs

Physical Memory Manager (PMM)

pmm::PhysicalMemoryManager

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)?;

memory::init::init_memory()

Initializes the memory subsystem.

pub fn init_memory(multiboot_info: usize, allocator: &PmmAllocator) -> KernelResult<()>

Usage:

memory::init::init_memory(multiboot_info, &ALLOCATOR)?;

Virtual Memory Manager (VMM)

vmm::VirtualMemoryManager

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)?;

Task Management APIs

Task Structure

task::Task

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(),
};

Scheduler

task::scheduler::Scheduler

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 returns

Task Functions

task::spawn()

Convenience function to spawn a task.

pub fn spawn(func: fn(), name: &str) -> KernelResult<TaskId>

Usage:

task::spawn(my_function, "my_task")?;

VFS APIs

Inode Interface

vfs::inode::Inode

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)?;

File Operations

vfs::file::File

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)?;

Mount Namespace

vfs::mount::MountNamespace

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)?;

System Call APIs

Syscall Numbers

syscall::numbers::SyscallNumber

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,
}

Syscall Handler

syscall::handler::handle_syscall()

Handles system calls from user mode.

pub fn handle_syscall(num: u32, args: &[usize; 6]) -> SyscallResult

Usage:

// Called from interrupt handler
let result = handle_syscall(syscall_num, &args);

Available System Calls

sys_exit()

Terminates the current task.

pub fn sys_exit(status: i32) -> !;

sys_write()

Writes to a file descriptor.

pub fn sys_write(fd: u32, buf: *const u8, count: usize) -> isize;

sys_read()

Reads from a file descriptor.

pub fn sys_read(fd: u32, buf: *mut u8, count: usize) -> isize;

sys_open()

Opens a file.

pub fn sys_open(path: *const u8, flags: u32) -> u32;

Error Handling APIs

KernelError

error::KernelError

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,
}

error::KernelResult<T>

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)
}

Common Patterns

Error Propagation

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(())
}

Resource Management

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));
        });
    }
}

Initialization Patterns

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()
    }
}

Thread Safety

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;
}

Best Practices for API Usage

  1. Always handle errors - Never ignore KernelResult
  2. Use RAII - Implement Drop for resource cleanup
  3. Document unsafe code - Use // SAFETY: comments
  4. Prefer safe abstractions - Use safe Rust when possible
  5. Check initialization - Verify modules are initialized before use
  6. Use appropriate lifetimes - Avoid unnecessary static references
  7. 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.