Initial userboot support
Some checks failed
Continuous Integration / Check (push) Failing after 43s
Continuous Integration / Clippy (push) Failing after 41s

This commit is contained in:
August 2026-06-30 21:25:33 +00:00
parent c6e032d9c9
commit 77355d3f25
Signed by: shibedrill
SSH Key Fingerprint: SHA256:M0m3JW1s38BgO2t0fG146Yxd9OJ2IOqkvCAsuRHQ6Pw
17 changed files with 79 additions and 62 deletions

2
Cargo.lock generated
View File

@ -69,7 +69,7 @@ checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"
[[package]] [[package]]
name = "gila" name = "gila"
version = "0.3.2" version = "0.4.0"
dependencies = [ dependencies = [
"acid_alloc", "acid_alloc",
"enumflags2", "enumflags2",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "gila" name = "gila"
version = "0.3.2" version = "0.4.0"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
@ -28,6 +28,10 @@ test = false
doctest = false doctest = false
bench = false bench = false
[[bin]]
name = "userboot"
path = "src/userboot/main.rs"
[lib] [lib]
name = "libgila" name = "gila"
path = "src/lib/lib.rs" path = "src/lib/lib.rs"

View File

@ -84,23 +84,35 @@ args = ["build", "--profile", "${PROFILE}", "--lib"]
[tasks.kernel] [tasks.kernel]
condition = { files_modified = { input = [ condition = { files_modified = { input = [
"src/kernel/**/*.rs", "src/kernel/**/*.rs",
"src/kernel/**/*.ld", "src/linker_scripts/**/*.ld",
"${ARTIFACTDIR}/libgila.rlib" "${ARTIFACTDIR}/libgila.rlib"
], output = ["${ARTIFACTDIR}/kernel"] }, fail_message = "(inputs unchanged)" } ], output = ["${ARTIFACTDIR}/kernel"] }, fail_message = "(inputs unchanged)" }
dependencies = ["lib"] dependencies = ["lib"]
command = "cargo" command = "cargo"
args = ["build", "--profile", "${PROFILE}", "--bin", "kernel"] args = ["build", "--profile", "${PROFILE}", "--bin", "kernel"]
[tasks.userboot]
condition = { files_modified = { input = [
"src/userboot/**/*.rs",
"src/linker_scripts/**/*.ld",
"${ARTIFACTDIR}/libgila.rlib"
], output = ["${ARTIFACTDIR}/userboot"] }, fail_message = "(inputs unchanged)" }
dependencies = ["lib"]
command = "cargo"
args = ["build", "--profile", "${PROFILE}", "--bin", "userboot"]
[tasks.iso] [tasks.iso]
condition = { files_modified = { input = [ condition = { files_modified = { input = [
"${ARTIFACTDIR}/kernel", "${ARTIFACTDIR}/kernel",
"${ARTIFACTDIR}/userboot",
"configs/limine.conf", "configs/limine.conf",
"resources/wallpaper.png",
"${LIMINEDIR}/limine-bios.sys", "${LIMINEDIR}/limine-bios.sys",
"${LIMINEDIR}/limine-bios-cd.bin", "${LIMINEDIR}/limine-bios-cd.bin",
"${LIMINEDIR}/limine-uefi-cd.bin", "${LIMINEDIR}/limine-uefi-cd.bin",
"${LIMINEDIR}/${LIMINEBIN}" "${LIMINEDIR}/${LIMINEBIN}"
], output = ["build/gila.iso"] }, fail_message = "(inputs unchanged)" } ], output = ["build/gila.iso"] }, fail_message = "(inputs unchanged)" }
dependencies = ["kernel"] dependencies = ["kernel", "userboot"]
script = ''' script = '''
mkdir -p build/iso/boot/limine mkdir -p build/iso/boot/limine
mkdir -p build/iso/EFI/BOOT mkdir -p build/iso/EFI/BOOT
@ -113,7 +125,8 @@ script = '''
cp -f ${LIMINEDIR}/limine-uefi-cd.bin build/iso/boot/limine/ cp -f ${LIMINEDIR}/limine-uefi-cd.bin build/iso/boot/limine/
cp -f ${LIMINEDIR}/${LIMINEBIN} build/iso/EFI/BOOT cp -f ${LIMINEDIR}/${LIMINEBIN} build/iso/EFI/BOOT
cp -f ${ARTIFACTDIR}/kernel build/iso/boot/${ARCH}/gila cp -f ${ARTIFACTDIR}/kernel build/iso/boot/${ARCH}/kernel
cp -f ${ARTIFACTDIR}/userboot build/iso/boot/${ARCH}/userboot
xorriso -as mkisofs \ xorriso -as mkisofs \
-b boot/limine/limine-bios-cd.bin \ -b boot/limine/limine-bios-cd.bin \

View File

@ -1,6 +1,6 @@
# Gila v0.3.1 - a Rust Microkernel # Gila v0.4.0 - a Rust Microkernel
![An illustrated Gila monster, and the text "Gila: A Minimal Rust Microkernel", superimposed over some serial log output.](gila_banner.png) ![An illustrated Gila monster, and the text "Gila: A Minimal Rust Microkernel", superimposed over some serial log output.](resources/gila_banner.png)
Gila is a Rust microkernel OS, inspired by microkernel projects such as seL4, Zircon, and Redox. I aim to implement multitasking, userspace drivers, IPC, and sandboxing. I do not aim to make it POSIX-compatible, but it will likely end up sharing many features with POSIX operating systems. Its design philosophy is focused around simplicity, isolation, modularity, and minimal privilege. Gila is a Rust microkernel OS, inspired by microkernel projects such as seL4, Zircon, and Redox. I aim to implement multitasking, userspace drivers, IPC, and sandboxing. I do not aim to make it POSIX-compatible, but it will likely end up sharing many features with POSIX operating systems. Its design philosophy is focused around simplicity, isolation, modularity, and minimal privilege.

View File

@ -1,7 +1,7 @@
fn main() { fn main() {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
// Tell cargo to pass the linker script to the linker.. // Tell cargo to pass the linker script to the linker..
println!("cargo:rustc-link-arg=-Tsrc/kernel/arch/{arch}/linker.ld"); println!("cargo:rustc-link-arg=-Tsrc/linker_scripts/{arch}/linker.ld");
// ..and to re-run if it changes. // ..and to re-run if it changes.
println!("cargo:rerun-if-changed=src/kernel/arch/{arch}linker.ld"); println!("cargo:rerun-if-changed=src/linker_scripts/{arch}linker.ld");
} }

View File

@ -1,6 +0,0 @@
[deployment]
libgila_version = "0.1.0"
arch = "x86_64"
# Optional
name = "example"
version = "0.1.0"

View File

@ -1,10 +1,11 @@
timeout: 1 timeout: 1
wallpaper: boot():/bg.png wallpaper: boot():/wallpaper.png
wallpaper_style: centered wallpaper_style: centered
/Gila /Gila
protocol: limine protocol: limine
kernel_path: boot():/boot/${ARCH}/gila kernel_path: boot():/boot/${ARCH}/kernel
cmdline: -loglevel=Info -logdev=display,serial -initramfs=/boot/${ARCH}/initramfs.tar.lzma cmdline: -loglevel=Trace -logdev=display,serial
module_path: boot():/boot/${ARCH}/userboot
kaslr: yes kaslr: yes
randomize_hhdm_base: yes randomize_hhdm_base: yes

View File

@ -7,41 +7,43 @@ design details can be found in [SECURITY.md](SECURITY.md).
## Navigating ## Navigating
- [kernel/src/](../kernel/src/): Kernel-specific code. - [src/kernel/](../src/kernel/): Kernel-specific code.
- [arch/](../kernel/src/arch/): Architecture specific features like the - [arch/](../src/kernel/arch/): Architecture specific features like the
display, serial, and interrupts. Each architecture is a subfolder, display, serial, and interrupts. Each architecture is a subfolder,
containing a file or module for each feature. containing a file or module for each feature.
- [boot/](../kernel/src/boot/mod.rs): Handles bootloader-managed data - [boot/](../src/kernel/boot/mod.rs): Handles bootloader-managed data
structures. Gila uses Limine. Other bootloaders are NOT supported. structures. Gila uses Limine. Other bootloaders are NOT supported.
- [params.rs](../kernel/src/boot/params.rs): Command line parameter parsing. - [params.rs](../src/kernel/boot/params.rs): Command line parameter parsing.
- [modules.rs](../kernel/src/boot/modules.rs): Kernel module handling. - [modules.rs](../src/kernel/boot/modules.rs): Kernel module handling.
- [constants.rs](../kernel/src/constants.rs): Constants referenced elsewhere - [constants.rs](../src/kernel/constants.rs): Constants referenced elsewhere
in the kernel. in the kernel.
- [log.rs](../kernel/src/log.rs): Logging structures, macros, and singletons - [log.rs](../src/kernel/log.rs): Logging structures, macros, and singletons
for logging to serial or the display. for logging to serial or the display.
- [interrupt/](../kernel/src/interrupt/mod.rs): Interrupt handlers with - [interrupt/](../src/kernel/interrupt/mod.rs): Interrupt handlers with
platform-agnostic APIs. platform-agnostic APIs.
- [main.rs](../kernel/src/main.rs): The entry point that gets called by the - [main.rs](../src/kernel/main.rs): The entry point that gets called by the
bootloader. bootloader.
- [memory.rs](../kernel/src/memory.rs): Types relating to memory regions and - [memory.rs](../src/kernel/memory.rs): Types relating to memory regions and
allocation. allocation.
- [panic.rs](../kernel/src/panic.rs): The panic handler and associated - [panic.rs](../src/kernel/panic.rs): The panic handler and associated
functionality. functionality.
- [process.rs](../kernel/src/process.rs): Process types and functions. - [process.rs](../src/kernel/process.rs): Process types and functions.
- [syscall\_runner.rs](../kernel/src/syscall_runner.rs): Chooses a system call - [syscall\_runner.rs](../src/kernel/syscall_runner.rs): Chooses a system call
by its ID and defers actual syscall execution to code in `/libgila/src/`. by its ID and defers actual syscall execution to code in `/src/lib/`.
- [libgila/src/](../libgila/src/lib.rs): Shared between the kernel and any - [src/userboot/](../src/userboot/): The first Ring 3 binary to run.
- [src/linker_scripts](../src/linker_scripts/): Linker scripts for binaries.
- [src/lib/](../src/lib/lib.rs): Shared between the kernel and any
binaries built for it. Contains any definitions, structures, and types that will binaries built for it. Contains any definitions, structures, and types that will
cross the boundary between userspace and kernelspace, including those sent over IPC. cross the boundary between userspace and kernelspace, including those sent over IPC.
- [arch/](../libgila/src/arch/mod.rs): Architecture specific functionality like - [arch/](../src/lib/arch/mod.rs): Architecture specific functionality like
system call register storing/loading. system call register storing/loading.
- [syscall.rs](../libgila/src/syscall.rs): System call types common to apps and - [syscall.rs](../src/lib/syscall.rs): System call types common to apps and
the kernel. the kernel.
## Building and running ## Building and running
Building a bootable kernel is easy. All you need to do is run Building a bootable kernel is easy. All you need to do is run
`cargo build -p kernel`, and a valid, bootable Limine executable will be `cargo build --bin kernel`, and a valid, bootable Limine executable will be
generated. However, it cannot be booted without installing it in a bootable generated. However, it cannot be booted without installing it in a bootable
Limine filesystem, and it cannot do anything useful without an initramfs Limine filesystem, and it cannot do anything useful without an initramfs
containing system servers, such as the init server and device drivers. containing system servers, such as the init server and device drivers.
@ -72,18 +74,19 @@ If not, the following dependencies will need to be manually installed:
Run `cargo make` to invoke the [Makefile.toml](../Makefile.toml). Run `cargo make` to invoke the [Makefile.toml](../Makefile.toml).
- `cargo make clean_all`: Cleans all built binaries, libraries, initramfs - `cargo make clean_all`: Cleans all built binaries, libraries, and ISO build files.
files, and ISOs. - `cargo make clean_iso`: Cleans the ISO build directory.
- `cargo make lib`: Builds `libgila`, the library that the kernel and user - `cargo make lib`: Builds `libgila`, the library that the kernel and user
code are linked against. code are linked against.
- `cargo make kernel`: Builds the kernel ELF file. - `cargo make kernel`: Builds the kernel ELF file.
- `cargo make initramfs`: Build the init archive. - `cargo make userboot`: Build the userspace init binary.
- `cargo make iso`: Builds the bootable ISO with Limine installed. - `cargo make iso`: Builds the bootable ISO with Limine installed.
- `cargo make run`: Builds the ISO and boots it in QEMU. - `cargo make run`: Builds the ISO and boots it in QEMU.
- `cargo make gui_run`: Same as above, but with QEMU in GUI mode.
- `cargo make debug`: Launch the kernel in QEMU with debugging enabled, and - `cargo make debug`: Launch the kernel in QEMU with debugging enabled, and
start and connect GDB. start and connect GDB.
You do not need to clean any files after making changes. The `lib`, `kernel`, You do not need to clean any files after making changes. The `lib`, `kernel`, `userboot`,
and `iso` tasks will automatically be rerun if their input files change. and `iso` tasks will automatically be rerun if their input files change.
### Configuration ### Configuration
@ -139,16 +142,10 @@ one value supported. Current options are `Disabled`, `Trace`, `Info`,
- `-logdev`: A sequence of one or more values representing devices to log to. - `-logdev`: A sequence of one or more values representing devices to log to.
Current options are `display` and `serial`. This parameter is case Current options are `display` and `serial`. This parameter is case
insensitive. 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: The default behavior for each parameter, when not supplied, is:
`-loglevel=Info -initramfs=/boot/initramfs.tar.lzma` `-loglevel=Info`
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 ## Writing Programs for Gila

View File

@ -1,12 +0,0 @@
[package]
name = "libgila"
version = "0.1.0"
edition = "2024"
[dependencies]
num-derive = { version = "0.4.2", default-features = false }
num-traits = { version = "0.2.19", default-features = false }
[lib]
# Stop appending lib to artifact names!!! it's already a library!!!
name = "gila"

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 320 KiB

View File

@ -41,8 +41,7 @@ use crate::{
gdt::dump_gdt, gdt::dump_gdt,
interrupts::get_lapic_addr, interrupts::get_lapic_addr,
}, },
}, }, boot::modules::MODULE_RESPONSE, memory::paging::{self, active_root_table, map_page, phys_to_virt},
memory::paging::{self, active_root_table, map_page, phys_to_virt},
}; };
lazy_static! { lazy_static! {
@ -204,5 +203,12 @@ unsafe extern "C" fn main() -> ! {
let res = map_page(phys_to_virt(lapic), mapping); let res = map_page(phys_to_virt(lapic), mapping);
log_info!("Map status: {:?}", res); log_info!("Map status: {:?}", res);
if let Some(modules_list) = *MODULE_RESPONSE {
if modules_list.modules()[0].path().ends_with("/userboot") {
log_info!("Found userboot: {} {}", modules_list.modules()[0].path(), modules_list.modules()[0].cmdline());
log_info!("Start address: 0x{:x}", modules_list.modules()[0].data().as_ptr() as usize);
}
}
panic!("Finished boot, but cannot start init because processes not implemented!"); panic!("Finished boot, but cannot start init because processes not implemented!");
} }

14
src/userboot/main.rs Normal file
View File

@ -0,0 +1,14 @@
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[unsafe(no_mangle)]
unsafe extern "C" fn main() -> ! {
loop {}
}
#[panic_handler]
pub fn panic(info: &PanicInfo) -> ! {
loop {}
}