mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
docs: restructure architecture documentation and add new guides
This commit is contained in:
parent
bbc5a44982
commit
5af02da5a1
10 changed files with 226 additions and 4 deletions
|
|
@ -13,10 +13,33 @@ The documentation is organized into three main categories:
|
||||||
|
|
||||||
### 1. [Architecture](architecture/)
|
### 1. [Architecture](architecture/)
|
||||||
Explains the logical layout of the kernel and internal components.
|
Explains the logical layout of the kernel and internal components.
|
||||||
- [`Core`](architecture/core.md): Kernel source layout and the boot process (Limine, Multiboot2).
|
|
||||||
- [`Memory`](architecture/memory.md): Physical Memory Management (PMM) and Virtual Memory Management (VMM).
|
#### System
|
||||||
- [`Filesystem`](architecture/filesystem.md): Virtual File System (VFS) and the RAM-based FAT32 simulation.
|
- [`Core`](architecture/system/core.md): Kernel source layout and the boot process (Limine, Multiboot2).
|
||||||
- [`Window Manager`](architecture/window_manager.md): How the built-in Window Manager natively handles graphics, events, and compositing.
|
- [`Processes & Scheduling`](architecture/system/processes.md): Multitasking, context switching, and ELF loading.
|
||||||
|
- [`Interrupts & Exceptions`](architecture/system/interrupts.md): IDT, GDT, and exception handling.
|
||||||
|
|
||||||
|
#### Memory
|
||||||
|
- [`Memory (PMM/VMM)`](architecture/memory/memory.md): Physical Memory Management and Virtual Memory Management.
|
||||||
|
- [`Memory Manager`](architecture/memory/memory_manager.md): Slab allocator and block allocator for kernel heap.
|
||||||
|
|
||||||
|
#### Storage & Filesystems
|
||||||
|
- [`Filesystem`](architecture/storage/filesystem.md): Virtual File System (VFS) and the RAM-based FAT32 simulation.
|
||||||
|
- [`AHCI Drivers`](architecture/storage/ahci_drivers.md): Hardware communication for block storage devices.
|
||||||
|
|
||||||
|
#### Network
|
||||||
|
- [`Network Stack`](architecture/network/network_stack.md): TCP/IP implementation and socket APIs.
|
||||||
|
- [`Network Drivers`](architecture/network/network_drivers.md): Hardware interaction for network cards (e.g. e1000).
|
||||||
|
|
||||||
|
#### Graphics
|
||||||
|
- [`Window Manager`](architecture/graphics/window_manager.md): Compositor, events, and overlapping windows.
|
||||||
|
- [`Rendering`](architecture/graphics/rendering.md): Framebuffer, font rendering, and image loading.
|
||||||
|
|
||||||
|
#### Hardware
|
||||||
|
- [`PCI`](architecture/hardware/pci.md): PCI bus enumeration and device binding.
|
||||||
|
- [`Input`](architecture/hardware/input.md): PS/2 Keyboard and Mouse input handling.
|
||||||
|
|
||||||
|
#### Misc
|
||||||
- [`Versioning`](architecture/versioning.md): The OS date-based version scheme (`YY.M[.x]`) and kernel semantic versioning (`MAJOR.MINOR.PATCH`).
|
- [`Versioning`](architecture/versioning.md): The OS date-based version scheme (`YY.M[.x]`) and kernel semantic versioning (`MAJOR.MINOR.PATCH`).
|
||||||
|
|
||||||
### 2. [Building and Deployment](build/)
|
### 2. [Building and Deployment](build/)
|
||||||
|
|
|
||||||
41
docs/architecture/hardware/pci.md
Normal file
41
docs/architecture/hardware/pci.md
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# PCI Bus Subsystem
|
||||||
|
|
||||||
|
The Peripheral Component Interconnect (PCI) subsystem in BoredOS is responsible for discovering, enumerating, and configuring hardware devices connected to the motherboard. It provides the foundation for the OS to load specific device drivers (like Network Interface Cards or AHCI controllers).
|
||||||
|
|
||||||
|
## 1. Configuration Space Access
|
||||||
|
|
||||||
|
BoredOS interacts with the PCI bus via the legacy x86 I/O ports:
|
||||||
|
- **`0xCF8`**: Address Port (used to select a specific bus, device, function, and register offset).
|
||||||
|
- **`0xCFC`**: Data Port (used to read or write the 32-bit value at the selected address).
|
||||||
|
|
||||||
|
These are abstracted in `src/dev/pci.c` by the `pci_read_config()` and `pci_write_config()` functions. By writing a formatted 32-bit address to `0xCF8`, the CPU signals the PCI bridge to route the subsequent data read/write on `0xCFC` to the correct hardware device.
|
||||||
|
|
||||||
|
## 2. Device Enumeration
|
||||||
|
|
||||||
|
During boot, BoredOS recursively scans the PCI buses. The PCI bus topology is hierarchical:
|
||||||
|
- Up to **256 buses**.
|
||||||
|
- Each bus has up to **32 devices**.
|
||||||
|
- Each device has up to **8 functions** (for multi-function devices).
|
||||||
|
|
||||||
|
The enumeration process (`pci_enumerate_devices`):
|
||||||
|
1. Iterates through Bus 0 to 255.
|
||||||
|
2. For each bus, iterates through Devices 0 to 31.
|
||||||
|
3. For each device, it reads the `Vendor ID` at offset 0. If the value is `0xFFFF`, no device is present at that slot.
|
||||||
|
4. If a valid Vendor ID is found, it populates a `pci_device_t` structure containing the:
|
||||||
|
- `Vendor ID` and `Device ID` (used to uniquely identify the hardware model).
|
||||||
|
- `Class Code`, `Subclass`, and `Prog IF` (used to identify the generic type of the device, e.g., Network Controller, Mass Storage Controller).
|
||||||
|
|
||||||
|
## 3. Base Address Registers (BARs)
|
||||||
|
|
||||||
|
PCI devices expose memory-mapped I/O (MMIO) regions or I/O port ranges via Base Address Registers (BARs).
|
||||||
|
BoredOS provides the `pci_get_bar(dev, bar_num)` function to extract these base addresses.
|
||||||
|
|
||||||
|
Drivers use BARs to talk directly to the hardware. For example:
|
||||||
|
- The AHCI driver reads BAR5 to find the base address of the AHCI memory registers (ABAR).
|
||||||
|
- The E1000 driver uses a BAR to map the NIC's control registers into the kernel's virtual memory space.
|
||||||
|
|
||||||
|
## 4. Hardware Configuration
|
||||||
|
|
||||||
|
Once a device is found, drivers can call helper functions to enable specific PCI features:
|
||||||
|
- **`pci_enable_bus_mastering(dev)`**: Sets the Bus Master bit in the PCI Command Register. This is critical for drivers that use DMA (Direct Memory Access), allowing the hardware to read/write system RAM independently of the CPU (used heavily by AHCI and Network drivers).
|
||||||
|
- **`pci_enable_mmio(dev)`**: Sets the Memory Space Enable bit, allowing the CPU to access the device's MMIO regions.
|
||||||
52
docs/architecture/network/network_stack.md
Normal file
52
docs/architecture/network/network_stack.md
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Networking Stack
|
||||||
|
|
||||||
|
BoredOS features a robust networking stack capable of handling Ethernet, IPv4, TCP, UDP, ICMP, DHCP, and DNS. The stack is built on top of the **lwIP (Lightweight IP)** library, which is integrated with a custom hardware driver layer.
|
||||||
|
|
||||||
|
## 1. Architecture Overview
|
||||||
|
|
||||||
|
The network stack is split into three main layers:
|
||||||
|
1. **Hardware/Driver Layer (`src/net/nic/`)**: Communicates with physical and virtual Network Interface Cards (NICs), handling raw Ethernet frame transmission and reception. Supported drivers include the Intel E1000 (`e1000.c`), Realtek RTL8139 (`rtl8139.c`), Realtek RTL8111 (`rtl8111.c`), and VirtIO network devices (`virtio_net.c`). A generic interface is provided via `nic.c`.
|
||||||
|
2. **Protocol Layer (lwIP)**: Processes Ethernet frames, handles ARP resolution, routes IPv4 packets, and manages TCP state machines.
|
||||||
|
3. **OS Interface Layer (`src/net/network.c`)**: Wraps the asynchronous lwIP API into a synchronous, easy-to-use API for BoredOS applications and the kernel.
|
||||||
|
|
||||||
|
## 2. Initialization & Polling
|
||||||
|
|
||||||
|
### `network_init()`
|
||||||
|
When the kernel boots, it initializes the network subsystem by:
|
||||||
|
1. Probing the PCI bus for supported NICs (e.g., the Intel E1000).
|
||||||
|
2. Initializing the lwIP core (`lwip_init()`) and DNS subsystem.
|
||||||
|
3. Binding the hardware NIC to lwIP using `netif_add`.
|
||||||
|
4. Automatically attempting to acquire an IP address via DHCP (`network_dhcp_acquire()`).
|
||||||
|
|
||||||
|
### The Polling Mechanism (`network_process_frames`)
|
||||||
|
Unlike some operating systems that process network packets entirely inside hardware interrupt handlers, BoredOS uses a **polled approach** to avoid re-entrancy issues in the TCP/IP stack.
|
||||||
|
|
||||||
|
The `network_process_frames()` function is called periodically (e.g., from the Window Manager loop or during blocking network calls). It calls:
|
||||||
|
- `nic_netif_poll()`: Pulls raw packets from the NIC ring buffer and feeds them to lwIP (`ethernet_input`).
|
||||||
|
- `sys_check_timeouts()`: Fires lwIP internal timers for TCP retransmissions, ARP cache expiration, and DHCP lease renewals.
|
||||||
|
|
||||||
|
A `network_processing` flag acts as a lightweight spinlock to prevent nested execution of the network poll loop.
|
||||||
|
|
||||||
|
## 3. TCP Implementation & Application API
|
||||||
|
|
||||||
|
While lwIP provides a callback-based raw API, BoredOS wraps this into a sequential API for userland applications.
|
||||||
|
|
||||||
|
Currently, the OS supports **one active TCP connection globally across the entire system**. The connection state is managed via a global Protocol Control Block (`current_tcp_pcb`). To prevent unauthorized cleanup, the OS tracks which process initiated the connection (`tcp_owner_pid`). If a new process attempts to connect while a connection is active, the existing connection is forcefully aborted.
|
||||||
|
|
||||||
|
### `network_tcp_connect(ip, port)`
|
||||||
|
1. Allocates a new Protocol Control Block (`tcp_new()`).
|
||||||
|
2. Registers callbacks for receive (`tcp_recv_callback`), error, and connection success.
|
||||||
|
3. Blocks (while polling the network) until the connection succeeds or times out after 15 seconds.
|
||||||
|
|
||||||
|
### `network_tcp_recv(buf, max_len)`
|
||||||
|
When packets arrive, `tcp_recv_callback` chains them into a `tcp_recv_queue` (`struct pbuf`).
|
||||||
|
The `network_tcp_recv` function blocks until data is available in this queue, then copies it into the application's buffer and frees the `pbuf`. A non-blocking variant (`network_tcp_recv_nb`) is also provided.
|
||||||
|
|
||||||
|
### Process Cleanup (`network_cleanup`)
|
||||||
|
If an application crashes or exits without closing its socket, the kernel's process manager calls `network_cleanup()`. This checks if the exiting process owns the current TCP PCB (`tcp_owner_pid`) and forcibly aborts the connection to prevent resource leaks.
|
||||||
|
|
||||||
|
## 4. Helper Protocols
|
||||||
|
|
||||||
|
- **DHCP:** Managed entirely by lwIP. BoredOS simply waits up to 10 seconds during boot for a lease.
|
||||||
|
- **DNS (`network_dns_lookup`):** Uses lwIP's `dns_gethostbyname`. It blocks and polls until the callback is triggered with the resolved IP address.
|
||||||
|
- **ICMP (Ping):** The kernel provides a `network_icmp_single_ping` function using an lwIP raw socket (`raw_pcb`) to construct, checksum, and transmit an ICMP Echo Request, blocking until a reply is received to calculate the Round-Trip Time (RTT).
|
||||||
40
docs/architecture/storage/ahci_drivers.md
Normal file
40
docs/architecture/storage/ahci_drivers.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# AHCI Storage Driver
|
||||||
|
|
||||||
|
BoredOS implements an Advanced Host Controller Interface (AHCI) driver to interface with Serial ATA (SATA) mass storage devices. The driver is located in `src/dev/ahci.c` and allows the OS to read and write sectors directly to physical hard drives or solid-state drives using DMA (Direct Memory Access).
|
||||||
|
|
||||||
|
## 1. Discovery and Initialization
|
||||||
|
|
||||||
|
The AHCI initialization process (`ahci_init`) starts by querying the PCI subsystem:
|
||||||
|
1. It searches for a PCI device with Class `0x01` (Mass Storage) and Subclass `0x06` (SATA).
|
||||||
|
2. It calls `pci_enable_bus_mastering` and `pci_enable_mmio` to ensure the controller can perform DMA and its registers are accessible.
|
||||||
|
3. It retrieves the **ABAR** (AHCI Base Address Register) from PCI BAR5.
|
||||||
|
4. The ABAR points to the `HBA_MEM` structure (Host Bus Adapter Memory Registers). The kernel iterates through the `pi` (Ports Implemented) bitmask to find active SATA ports.
|
||||||
|
|
||||||
|
## 2. Port Configuration
|
||||||
|
|
||||||
|
For every active SATA port found, the driver must allocate memory structures that the hardware will use to process commands:
|
||||||
|
1. **Command List Base (`clb`)**: A 1KB memory region holding 32 Command Headers.
|
||||||
|
2. **FIS Base (`fb`)**: A 256-byte memory region where the HBA writes incoming Frame Information Structures (FIS) from the drive.
|
||||||
|
3. **Command Tables (`ctba`)**: A larger memory region allocated for each Command Header, containing the actual SATA command bytes and the scatter/gather lists (PRDT).
|
||||||
|
|
||||||
|
*Note:* All AHCI data structures must be allocated in physically contiguous memory and properly aligned (e.g., 1KB or 256-byte boundaries) because the HBA reads them directly from physical RAM via DMA.
|
||||||
|
|
||||||
|
## 3. Physical Region Descriptor Tables (PRDT)
|
||||||
|
|
||||||
|
When reading or writing data, BoredOS must tell the AHCI controller where in RAM the data should be stored or fetched. This is done using PRDT entries.
|
||||||
|
|
||||||
|
Each `HBA_PRDT_ENTRY` specifies:
|
||||||
|
- A physical Data Base Address (`dba`).
|
||||||
|
- A Byte Count (`dbc`), limited to a maximum of 4MB per entry.
|
||||||
|
|
||||||
|
If a read/write request spans multiple fragmented pages or exceeds 4MB, the driver constructs multiple PRDT entries within the Command Table to form a scatter/gather list. The AHCI hardware seamlessly processes these entries as a single contiguous disk operation.
|
||||||
|
|
||||||
|
## 4. Reading and Writing Sectors
|
||||||
|
|
||||||
|
To execute a command (e.g., `ahci_read_sectors` or `ahci_write_sectors`):
|
||||||
|
1. The driver finds a free slot in the Command List.
|
||||||
|
2. It populates the Command Header, setting the `cfl` (Command FIS Length) and `w` (Write) bit.
|
||||||
|
3. It builds a Host-to-Device Register FIS (`FIS_REG_H2D`) in the Command Table, issuing the `ATA_CMD_READ_DMA_EX` or `ATA_CMD_WRITE_DMA_EX` command and specifying the starting LBA (Logical Block Address) and sector count.
|
||||||
|
4. It sets up the PRDT entries pointing to the physical memory of the provided buffer.
|
||||||
|
5. It sets the corresponding bit in the Port's Command Issue register (`ci`).
|
||||||
|
6. The driver then polls the `ci` register (or waits for an interrupt) until the bit clears, indicating the hardware has completed the DMA transfer.
|
||||||
66
docs/architecture/system/processes.md
Normal file
66
docs/architecture/system/processes.md
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Process Management & Scheduling
|
||||||
|
|
||||||
|
BoredOS implements a lightweight, symmetric multiprocessing (SMP) capable multitasking environment. This document outlines the architecture of the scheduler, process structures, context switching, and ELF binary loading.
|
||||||
|
|
||||||
|
## 1. Process Structure (`process_t`)
|
||||||
|
|
||||||
|
The core of the process management system is the `process_t` structure, defined in `src/sys/process.h`. Due to kernel memory constraints, BoredOS supports a maximum of 16 concurrent processes (`MAX_PROCESSES`), stored in a statically allocated array.
|
||||||
|
|
||||||
|
Key fields include:
|
||||||
|
- **Identification:** `pid`, `parent_pid`, `pgid` (Process Group ID), and `name`.
|
||||||
|
- **Memory & Context:**
|
||||||
|
- `rsp`: The saved stack pointer during a context switch.
|
||||||
|
- `pml4_phys`: The physical address of the Page Map Level 4 table (VMM root) for this process.
|
||||||
|
- `kernel_stack` & `user_stack_alloc`: Pointers to allocated stack memory.
|
||||||
|
- **Scheduler State:** `ticks`, `sleep_until`, `is_idle`, `cpu_affinity`.
|
||||||
|
- **Resources:**
|
||||||
|
- `fds`: File descriptor table tracking open files, pipes, and sockets (up to `MAX_PROCESS_FDS` = 16).
|
||||||
|
- `gui_events`: A circular queue for Window Manager events (keyboard, mouse).
|
||||||
|
- **Signals:** POSIX-like signal tracking via `signal_mask` and `signal_pending`.
|
||||||
|
|
||||||
|
## 2. The Scheduler
|
||||||
|
|
||||||
|
BoredOS uses a **Preemptive Round-Robin** scheduler implemented as a circular linked list.
|
||||||
|
|
||||||
|
### Symmetric Multiprocessing (SMP)
|
||||||
|
Each CPU core maintains its own `current_process` pointer (`current_process[my_cpu]`). When a new user process is spawned via `process_create_elf`, the kernel assigns it to an Application Processor (AP) core using a simple round-robin assignment policy (`next_cpu_assign`), avoiding Core 0 (BSP) which is typically reserved for kernel tasks and driver interrupts.
|
||||||
|
|
||||||
|
### The `process_schedule` Loop
|
||||||
|
When the timer interrupt fires, it calls `process_schedule(current_rsp)`:
|
||||||
|
1. It saves the `current_rsp` into the current process's structure.
|
||||||
|
2. It handles cleanup of killed processes (`kill_pending`).
|
||||||
|
3. It traverses the circular linked list (`cur->next`) looking for a process where `cpu_affinity == my_cpu`.
|
||||||
|
4. It checks if the process is sleeping (`sleep_until > now`).
|
||||||
|
5. It switches the hardware context:
|
||||||
|
- Updates the Task State Segment (TSS) ring 0 stack pointer.
|
||||||
|
- Switches the page directory by writing the new `pml4_phys` to `CR3`.
|
||||||
|
- Returns the new process's `rsp`, which the interrupt handler then pops into registers.
|
||||||
|
|
||||||
|
## 3. Context Switching
|
||||||
|
|
||||||
|
Context switching is achieved by manually constructing an interrupt stack frame (IRETQ frame).
|
||||||
|
|
||||||
|
When a process is created, the kernel sets up the top of its kernel stack with:
|
||||||
|
- `SS` (Stack Segment: `0x1B` for user, `0x10` for kernel)
|
||||||
|
- `RSP` (The process's stack pointer)
|
||||||
|
- `RFLAGS` (`0x202` to ensure interrupts are enabled)
|
||||||
|
- `CS` (Code Segment: `0x23` for user, `0x08` for kernel)
|
||||||
|
- `RIP` (The entry point of the binary or function)
|
||||||
|
- Zeroed space for General Purpose Registers and a 512-byte `fxsave` region for FPU/SSE state.
|
||||||
|
|
||||||
|
When `process_schedule` returns the new `rsp`, the assembly interrupt stub uses `pop` instructions to restore the general-purpose registers, and finally executes `iretq`, transitioning execution to the new process seamlessly.
|
||||||
|
|
||||||
|
## 4. ELF Loading
|
||||||
|
|
||||||
|
Userland applications in BoredOS are standard 64-bit ELF binaries.
|
||||||
|
|
||||||
|
The function `process_create_elf` orchestrates this:
|
||||||
|
1. **Memory Allocation:** Creates a new PML4 page table for the user process.
|
||||||
|
2. **Parsing:** Calls `elf_load(filepath, pml4, &size)` to parse the ELF headers, allocate required physical memory, and copy the executable segments (text, data, bss) into the process's virtual address space at the locations specified by the ELF program headers.
|
||||||
|
3. **Stack Setup:** Allocates a 256KB user stack mapped at `0x800000`.
|
||||||
|
4. **Argument Passing:** Parses the `args_str` passed to the executable and pushes an `argv` array onto the newly allocated user stack.
|
||||||
|
5. **Execution:** Sets the stack frame's `RIP` to the ELF entry point and links the process into the scheduler's run queue.
|
||||||
|
|
||||||
|
## 5. Process Termination
|
||||||
|
|
||||||
|
When a process exits (or is killed), it is not immediately freed. The scheduler sets `kill_pending = true`. The actual destruction of the PML4 table and stack allocations is deferred to the next tick inside `process_schedule` to avoid freeing the memory of the code currently executing the cleanup.
|
||||||
Loading…
Reference in a new issue