Docs, linting
Some checks are pending
Continuous Integration / Rustfmt (push) Waiting to run
Continuous Integration / Clippy (push) Waiting to run
Continuous Integration / Build (x86_64) (push) Waiting to run
Continuous Integration / Check (push) Successful in 5m21s

This commit is contained in:
August 2025-09-24 23:40:55 -04:00
parent d61dd8383b
commit 65804ef56a
Signed by: shibedrill
GPG Key ID: 5FE0CB25945EFAA2
5 changed files with 97 additions and 72 deletions

View File

@ -13,7 +13,7 @@ Information on the build system, repo structure, features, configuration options
### Complete
- Builds for `aarch64`, `riscv64`, `x86_64`, and `loongarch64`
- ~~Builds for `aarch64`, `riscv64`, `x86_64`, and `loongarch64`~~
- Valid Limine kernel
- Boots on `x86_64` (both UEFI and BIOS)
- Kernel command line parameters
@ -32,6 +32,7 @@ Information on the build system, repo structure, features, configuration options
### Future/Desired
- Multi-architecture features
- Userspace binaries/processes
- Interprocess communication
- Driver server interface

View File

@ -2,8 +2,9 @@
Gila is a microkernel, and almost all functionality of the OS is relegated to
"server" processes. A server is a process that provides a specific
functionality, using a kernel-provided interface, and it is given a "seat" by
the kernel which processes may query to reference it and invoke its functions.
functionality. The means by which processes will locate services is still up
in the air as of right now, but I believe I want to implement something
similar to (if not compatible with) D-Bus.
## Boot Process
@ -39,27 +40,35 @@ The system, hence, can be configured in two ways:
## APIs
Processes access services similarly to the way the init process accesses
data from the file system. The process requests the ID of the server that
performs the function, and then communicates with it via IPC and shared
memory regions. APIs are to be defined in the standard library.
Processes will access services by means of a data bus, possibly similar to D-Bus.
In this model, processes would access information from services by making an
IPC call to the kernel, which would either serve as a D-Bus server or
delegate D-Bus stuff to a special server process. From there, the client
process may establish a connection to the system bus, and use that connection
to request services.
Conventions for local procedure calls and message busing will be worked on
soon.
For example, if a process wanted to request the kernel version, it could
access the service `site.shibedrill.Gila`, the object path `/site/shibedrill/Gila/Kernel`,
and the property `site.shibedrill.Gila.Kernel.Version`. If the same process
wanted to access the vendor ID of a specific PCI device, it could access
service `site.shibedrill.Pci`, object `/site/shibedrill/Pci/Device/07/00/0`, and
property `site.shibedrill.Pci.Device.Vendor`. This property would be present
in all PCI devices, as it would be defined in an interface common to all PCI
device objects in the service's namespace.
## Device Drivers
Device driver assignment is performed like so:
Device drivers, in this userspace concept, are initialized as-needed. If a
process requests a service provided by a driver that is not yet running, a
privileged process (or the kernel) will initialize a device driver process.
If the relevant device is present, the kernel will map the necessary portions
of physical memory into the driver's address space, and return information on
the mappings to the new driver. If the device does not exist, the message bus
will return an error.
- The kernel obtains necessary hardware topology info from ACPI or the DTB.
- For each device, the kernel spawns a driver process based on a compatibility
list that details which drivers work for which devices.
- The driver process, when it initializes, requests information from the
kernel about the device. The kernel maps relevant regions of physical memory
into the process's memory space, and returns information on the new mappings
to the process.
- The driver then makes its functions available via IPC and shared memory.
- The kernel stores information about the driver to avoid spawning duplicates.
How the kernel will recognize whether a device is present, is still unknown.
Hopefully, a comprehensive enumeration system can be developed which does not
require device definitions to be built into the kernel.
## Servers vs. Shared Libraries

View File

@ -1,4 +1,3 @@
# Developer Resources
## Design Goals & Philosophy
@ -7,75 +6,80 @@ General design goals are outlined in [DESIGN.md](DESIGN.md). Security-relevant d
## Navigating
- [kernel/](src/kernel/): Kernel-specific code.
- [arch/](src/kernel/arch/): Architecture specific features like the display, serial, and interrupts. Each architecture is a subfolder, containing a file or module for each feature.
- [boot/](src/kernel/boot/mod.rs): Handles bootloader-managed data structures. Gila uses Limine. Other bootloaders are NOT supported.
- [params.rs](src/kernel/boot/params.rs): Command line parameter parsing.
- [modules.rs](src/kernel/boot/modules.rs): Kernel module handling.
- [constants.rs](src/kernel/constants.rs): Constants referenced elsewhere in the kernel.
- [device/](src/kernel/device/mod.rs): Functions for discovering hardware and assigning drivers.
-[acpi.rs](src/kernel/device/acpi.rs): ACPI handling functions and structures.
- [log.rs](src/kernel/log.rs): Logging structures, macros, and singletons for logging to serial or the display.
- [interrupt/](src/kernel/interrupt/mod.rs): Interrupt handlers with platform-agnostic APIs.
- [main.rs](src/kernel/main.rs): The entry point that gets called by the bootloader.
- [memory.rs](src/kernel/memory.rs): Types relating to memory regions and allocation.
- [panic.rs](src/kernel/panic.rs): The panic handler and associated functionality.
- [process.rs](src/kernel/process.rs): Process types and functions.
- [syscall_runner.rs](src/kernel/syscall_runner.rs): Chooses a system call by its ID and defers actual syscall execution to code in `src/lib/`.
- [lib/](src/lib/lib.rs): Library that all Gila's binary programs will be built against. Some of this code is shared with the kernel.
- [arch/](src/lib/arch/mod.rs): Architecture specific functionality like system call register storing/loading.
- [syscall.rs](src/lib/syscall.rs): System call types common to apps and the kernel.
* [kernel/](/src/kernel/): Kernel-specific code.
* [arch/](/src/kernel/arch/): Architecture specific features like the display, serial, and interrupts. Each architecture is a subfolder, containing a file or module for each feature.
* [boot/](/src/kernel/boot/mod.rs): Handles bootloader-managed data structures. Gila uses Limine. Other bootloaders are NOT supported.
* [params.rs](/src/kernel/boot/params.rs): Command line parameter parsing.
* [modules.rs](/src/kernel/boot/modules.rs): Kernel module handling.
* [constants.rs](/src/kernel/constants.rs): Constants referenced elsewhere in the kernel.
* [device/](/src/kernel/device/mod.rs): Functions for discovering hardware and assigning drivers.
-[acpi.rs](/src/kernel/device/acpi.rs): ACPI handling functions and structures.
* [log.rs](/src/kernel/log.rs): Logging structures, macros, and singletons for logging to serial or the display.
* [interrupt/](/src/kernel/interrupt/mod.rs): Interrupt handlers with platform-agnostic APIs.
* [main.rs](/src/kernel/main.rs): The entry point that gets called by the bootloader.
* [memory.rs](/src/kernel/memory.rs): Types relating to memory regions and allocation.
* [panic.rs](/src/kernel/panic.rs): The panic handler and associated functionality.
* [process.rs](/src/kernel/process.rs): Process types and functions.
* [syscall\_runner.rs](/src/kernel/syscall_runner.rs): Chooses a system call by its ID and defers actual syscall execution to code in `src/lib/`.
* [lib/](/src/lib/lib.rs): Library that all Gila's binary programs will be built against. Some of this code is shared with the kernel.
* [arch/](/src/lib/arch/mod.rs): Architecture specific functionality like system call register storing/loading.
* [syscall.rs](/src/lib/syscall.rs): System call types common to apps and the kernel.
## Building and running
Building a bootable kernel is easy. All you need to do is run `cargo build --bin kernel`, and a valid, bootable Limine executable will be generated. However, it cannot be booted without installing it in a bootable Limine filesystem, and it cannot do anything useful without an initramfs containing system servers, such as the init server and
device drivers.
Building a bootable kernel is easy. All you need to do is run
`cargo build --bin kernel`, and a valid, bootable Limine executable will be
generated. However, it cannot be booted without installing it in a bootable
Limine filesystem, and it cannot do anything useful without an initramfs
containing system servers, such as the init server and device drivers.
This project uses [cargo-make](https://github.com/sagiegurari/cargo-make) to handle building ISOs and managing files not associated with Cargo. You need to install it before you can build an ISO automatically. To do so, you can run `cargo install cargo-make`. In addition, you will also need:
- `rustup` command installed
- `limine` command installed
- `xorriso` command installed
- `qemu-system-{your target architecture}` command installed (for running)
* `rustup` command installed
* `limine` command installed
* `xorriso` command installed
* `qemu-system-{your target architecture}` command installed (for running)
Then run `cargo make` to invoke the [Makefile.toml](Makefile.toml).
- `cargo make clean_all`: Cleans all built binaries, libraries, initramfs files, and ISOs.
- `cargo make lib`: Builds `libgila`, the library that the kernel and user code are linked against.
- `cargo make kernel`: Builds the kernel ELF file.
- `cargo make initramfs`: Build the init archive.
- `cargo make iso`: Builds the bootable ISO with Limine installed.
- `cargo make run`: Builds the ISO and boots it in QEMU.
- `cargo make debug`: Launch the kernel in QEMU with debugging enabled, and start and connect GDB.
* `cargo make clean_all`: Cleans all built binaries, libraries, initramfs files, and ISOs.
* `cargo make lib`: Builds `libgila`, the library that the kernel and user code are linked against.
* `cargo make kernel`: Builds the kernel ELF file.
* `cargo make initramfs`: Build the init archive.
* `cargo make iso`: Builds the bootable ISO with Limine installed.
* `cargo make run`: Builds the ISO and boots it in QEMU.
* `cargo make debug`: Launch the kernel in QEMU with debugging enabled, and start and connect GDB.
You do not need to clean any files after making changes. The `lib`, `kernel`, and `iso` tasks will automatically be rerun if their input files change.
### Configuration
- Variable `LIMINEDIR`: Location of binary files for limine. Default is `/usr/share/limine`.
- Variable `TARGET`: rustc target triple to compile for. Default is `x86_64-unknown-none`. Options are listed [in the targets section](#targets).
- Argument `-p`: Rust build profile to use. Default is `dev`. Options are `dev` and `release`.
* Variable `LIMINEDIR`: Location of binary files for limine. Default is `/usr/share/limine`.
* Variable `TARGET`: rustc target triple to compile for. Default is `x86_64-unknown-none`. Options are listed [in the targets section](#targets).
* Argument `-p`: Rust build profile to use. Default is `dev`. Options are `dev` and `release`.
> [!NOTE]
> \[!NOTE]
> The `-p {profile}` argument must go between `cargo make` and the task argument.
### Features
Gila has four optional features, which I made optional in anticipation of a potential future port to older systems which might not support modern standards like UEFI or ACPI. They are all enabled by default. Disabling them reduces kernel size and forces the kernel to fall back to other implementations for some functionality like device discovery.
- `acpi`: Advanced Configuration and Power Interface, for device discovery & power management
- `dtb`: Device Tree Blob, for device discovery in embedded systems
- `compression`: Compressed initramfs archive
- `uefi`: Universal Extensible Firmware Interface specific bootloader features
* `acpi`: Advanced Configuration and Power Interface, for device discovery & power management
* `dtb`: Device Tree Blob, for device discovery in embedded systems
* `compression`: Compressed initramfs archive
* `uefi`: Universal Extensible Firmware Interface specific bootloader features
### Targets
Gila currently supports four different CPU architectures:
Gila ~~currently supports~~ aims to support four different CPU architectures:
- `x86_64`
- `aarch64`
- `riscv64`
- `loongarch64`
* `x86_64`
* `aarch64`
* `riscv64`
* `loongarch64`
It currently only builds on `x86_64`, and will continue to only support it until I can implement support for important features in other architectures.
All these architectures are supported by Limine, and the appropriate backends are present in the Makefile to compile and build bootable images for each. While Limine and rustc also support `IA32` (also referred to as `i686`), support is missing from the [Limine crate](https://crates.io/crates/limine). Compilation will fail if a build for an unsupported target is attempted.
@ -87,12 +91,16 @@ Kernel parameters are passed as part of the `cmdline` through [limine.conf](conf
List of current extant kernel parameters:
- `-loglevel`: Can be a number or string corresponding to a log level. Only one value supported. Current options are `Disabled`, `Trace`, `Info`, `Warning`, `Error`, and `Critical`. This parameter is case insensitive.
- `-logdev`: A sequence of one or more values representing devices to log to. Current options are `display` and `serial`. This parameter is case insensitive.
- `-initramfs`: A valid path to a module to serve as the initramfs (containing the init binary). Only one value supported. This parameter is case sensitive.
* `-loglevel`: Can be a number or string corresponding to a log level. Only one value supported. Current options are `Disabled`, `Trace`, `Info`, `Warning`, `Error`, and `Critical`. This parameter is case insensitive.
* `-logdev`: A sequence of one or more values representing devices to log to. Current options are `display` and `serial`. This parameter is case insensitive.
* `-initramfs`: A valid path to a module to serve as the initramfs (containing the init binary). Only one value supported. This parameter is case sensitive.
The default behavior for each parameter, when not supplied, is:
`-loglevel=Info -initramfs=/boot/initramfs.tar.lzma`
The `.lzma` extension is removed from the default initramfs name when compression is disabled. It must also be changed in [limine.conf](configs/limine.conf) or else Limine will not load it.
## Writing Programs for Gila
Gila's system calls will soon be fully defined in `libgila`. The library is developed in tandem with, and is used within, the kernel. As Gila does not currently support any kind of Rust or C standard library, you must compile your programs for the same architecture as Gila itself, bare metal. Userspace programs must not use any privileged instructions that would cause an exception if running in Ring 3 or any other least-privileged mode of a processor.

View File

@ -1,6 +1,10 @@
# Security
Part of the design philosophy that drives my inspiration for Gila is the idea of creating a new, fast, and safe kernel with security as a central focus. Kernels such as Linux, Mach, and NT have been around for too long to work perfectly with today's system security model. Gila is brand-new, and built almost exclusively in Rust for the utmost memory safety.
Part of the design philosophy that drives my inspiration for Gila is the idea
of creating a new, fast, and safe kernel with security as a central focus.
Kernels such as Linux, Mach, and NT have been around for too long to work
perfectly with today's system security model. Gila is brand-new, and built
almost exclusively in Rust for the utmost memory safety.
## Goals

View File

@ -1,21 +1,24 @@
// Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: GPL-3.0-or-later
use crate::format;
use lazy_static::lazy_static;
use x86_64::structures::idt::*;
use crate::format;
lazy_static! {
pub static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
// TODO: Re-implement this once the x86-interrupt ABI is fixed.
// Alternatively: Write our own interrupt handler wrappers.
// TODO: Rewrite using our own x86 interrupt wrapper
// code. The x86_interrupt ABI is always breaking, and this
// approach will fall apart once multiarch support is re-added.
idt.double_fault.set_handler_fn(double_fault);
idt.page_fault.set_handler_fn(page_fault);
idt
};
}
// Must do this to avoid unused function warning
#[allow(dead_code)]
extern "x86-interrupt" fn double_fault(info: InterruptStackFrame, _: u64) -> ! {
crate::interrupt::double_fault(format!("{info:#?}"));
}
@ -41,4 +44,4 @@ extern "x86-interrupt" fn page_fault(info: InterruptStackFrame, errcode: PageFau
crate::interrupt::page_fault(addr, info_formatted)
}
}
}
}