Port IO support, microkernel arch stuff
This commit is contained in:
parent
204c8e24ae
commit
df3ff681d0
56
ARCHITECTURE.md
Normal file
56
ARCHITECTURE.md
Normal file
@ -0,0 +1,56 @@
|
||||
# Architecture Outline
|
||||
|
||||
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.
|
||||
|
||||
# Boot Process
|
||||
|
||||
Gila initializes as a bare kernel, with the bootloader providing an init RAM
|
||||
filesystem in the form of a .tar.lzma archive. The kernel reads this file, and
|
||||
launches an init process (`/system/bin/init`). The init process has its own
|
||||
configuration file located at `/system/cfg/init.toml`, which should detail the
|
||||
steps needed to bring the system up to a multi-user status.
|
||||
|
||||
If the init system needs to access a filesystem, it must first get the handle
|
||||
of the filesystem server. If the filesystem server is not running when this
|
||||
handle request is made, the kernel will launch the server before returning its
|
||||
handle. From there, the filesystem server will request the handle of the disk
|
||||
driver that corresponds to the requested filesystem. The kernel then launches
|
||||
the disk driver server, and assigns it a seat based on the device it drives,
|
||||
granting it access to the memory region responsible for that device.
|
||||
|
||||
The benefit of this approach is threefold:
|
||||
|
||||
- The system does not need to include a filesystem OR disk driver, if neither
|
||||
the disk nor the filesystem are read or written.
|
||||
- The driver or filesystem server can crash, and the whole stack can recover.
|
||||
- The user or developer can trivially introduce new drivers without a reboot.
|
||||
This goes for filesystem drivers AND disk device drivers.
|
||||
|
||||
The system, hence, can be configured in two ways:
|
||||
|
||||
- The drivers can all be included in the initramfs for diskless operation.
|
||||
- The bare minimum drivers needed for disk access are included in the
|
||||
initramfs, and all other drivers are included in the root filesystem.
|
||||
|
||||
# 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.
|
||||
|
||||
# Device Drivers
|
||||
|
||||
Device driver assignment is performed like so:
|
||||
|
||||
- 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.
|
@ -18,44 +18,83 @@ env_scripts = [
|
||||
]
|
||||
|
||||
[env]
|
||||
# Directory for Limine binaries
|
||||
LIMINEDIR = "/usr/share/limine"
|
||||
# Compile target
|
||||
TARGET = "x86_64-unknown-none"
|
||||
# Binaries included in the OS initramfs
|
||||
BINS = []
|
||||
|
||||
[env.development]
|
||||
PROFILE = "dev"
|
||||
TARGETDIR = "debug"
|
||||
ARTIFACTDIR = "target/${TARGET}/${TARGETDIR}"
|
||||
|
||||
[env.release]
|
||||
PROFILE = "release"
|
||||
TARGETDIR = "release"
|
||||
ARTIFACTDIR = "target/${TARGET}/${TARGETDIR}"
|
||||
|
||||
[tasks.default]
|
||||
alias = "run"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[tasks.clean]
|
||||
dependencies = ["cleaniso"]
|
||||
dependencies = ["clean_iso", "clean_initramfs"]
|
||||
command = "cargo"
|
||||
args = ["clean"]
|
||||
|
||||
[tasks.prepare]
|
||||
script = "rustup install nightly; rustup target add ${TARGET}"
|
||||
|
||||
[tasks.cleaniso]
|
||||
[tasks.clean_iso]
|
||||
command = "rm"
|
||||
args = ["-rf", "build"]
|
||||
args = ["-rf", "build/iso", "build/gila.iso"]
|
||||
|
||||
[tasks.clean_initramfs]
|
||||
command = "rm"
|
||||
args = ["-rf", "build/initramfs", "build/initramfs.tar.lzma"]
|
||||
|
||||
[tasks.lib]
|
||||
condition = { files_modified = { input = ["./src/lib/**/*.rs"], output = ["./target/${TARGET}/${TARGETDIR}/libgila.rlib"] }, fail_message = "(inputs unchanged)"}
|
||||
condition = { files_modified = { input = ["src/lib/**/*.rs"], output = ["${ARTIFACTDIR}/libgila.rlib"] }, fail_message = "(inputs unchanged)" }
|
||||
dependencies = ["prepare"]
|
||||
command = "cargo"
|
||||
args = ["build", "--lib"]
|
||||
|
||||
[tasks.kernel]
|
||||
condition = { files_modified = { input = ["./src/kernel/**/*.rs", "./src/kernel/**/*.ld", "./target/${TARGET}/${TARGETDIR}/libgila.rlib"], output = ["./target/${TARGET}/${TARGETDIR}/kernel"] }, fail_message = "(inputs unchanged)"}
|
||||
condition = { files_modified = { input = [
|
||||
"src/kernel/**/*.rs",
|
||||
"src/kernel/**/*.ld",
|
||||
"${ARTIFACTDIR}/libgila.rlib"
|
||||
], output = ["${ARTIFACTDIR}/kernel"] }, fail_message = "(inputs unchanged)" }
|
||||
dependencies = ["lib"]
|
||||
command = "cargo"
|
||||
args = ["build", "--profile", "${PROFILE}", "--bin", "kernel"]
|
||||
|
||||
[tasks.bins]
|
||||
dependencies = []
|
||||
|
||||
[tasks.initramfs]
|
||||
condition = { files_modified = { input = [
|
||||
|
||||
], output = ["build/initramfs.tar.lzma"] }, fail_message = "(inputs unchanged)" }
|
||||
dependencies = ["bins"]
|
||||
script = '''
|
||||
mkdir -p build/initramfs/system/bin
|
||||
mkdir -p build/initramfs/system/cfg
|
||||
|
||||
for bin in $(echo ${BINS} | tr ";" " ")
|
||||
do
|
||||
cp ${ARTIFACTDIR}/$bin build/initramfs/system/bin/
|
||||
done
|
||||
cp server_config.toml build/initramfs/system/cfg/
|
||||
|
||||
tar -c --lzma -f build/initramfs.tar.lzma build/initramfs
|
||||
'''
|
||||
|
||||
[tasks.iso]
|
||||
condition = { files_modified = { input = [
|
||||
"./target/${TARGET}/${TARGETDIR}/kernel",
|
||||
@ -65,9 +104,8 @@ condition = { files_modified = { input = [
|
||||
"${LIMINEDIR}/limine-uefi-cd.bin",
|
||||
"${LIMINEDIR}/${LIMINEBIN}"
|
||||
], output = ["./build/gila.iso"] }, fail_message = "(inputs unchanged)" }
|
||||
dependencies = ["kernel"]
|
||||
dependencies = ["kernel", "initramfs"]
|
||||
script = '''
|
||||
#!@shell
|
||||
mkdir -p build/iso/boot/limine
|
||||
mkdir -p build/iso/EFI/BOOT
|
||||
|
||||
@ -76,8 +114,9 @@ script = '''
|
||||
cp -f ${LIMINEDIR}/limine-bios-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 ./build/initramfs.tar.lzma build/iso/boot/
|
||||
|
||||
cp -f target/${TARGET}/${TARGETDIR}/kernel build/iso/boot/
|
||||
cp -f ${ARTIFACTDIR}/kernel build/iso/boot/
|
||||
|
||||
mkdir -p build/iso/system/bin
|
||||
mkdir -p build/iso/system/tmp
|
||||
@ -100,4 +139,4 @@ script = '''
|
||||
[tasks.run]
|
||||
dependencies = ["iso"]
|
||||
command = "${QEMUCOMMAND}"
|
||||
args = ["-drive", "file=build/gila.iso,format=raw,index=0,media=disk"]
|
||||
args = ["-drive", "file=build/gila.iso,format=raw,index=0,media=disk", "-serial", "stdio"]
|
@ -4,3 +4,4 @@ timeout: 5
|
||||
protocol: limine
|
||||
kernel_path: boot():/boot/kernel
|
||||
cmdline: -loglevel=INFO -logdev=display,serial
|
||||
module_path: boot():/boot/initramfs.tar.lzma
|
||||
|
13
server_config.toml
Normal file
13
server_config.toml
Normal file
@ -0,0 +1,13 @@
|
||||
# The configuration file detailing which system servers
|
||||
# are responsible for what responsibilities.
|
||||
|
||||
# This configuration file details several tables. Each table
|
||||
# is a category of server the OS will launch to provide
|
||||
# userspace functionality. Each key in the table is a specific
|
||||
# functionality.
|
||||
|
||||
[filesystems]
|
||||
|
||||
[devices]
|
||||
|
||||
[services]
|
@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2025 shibedrill
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
mod ports;
|
||||
mod registers_impl;
|
||||
mod syscall_impl;
|
||||
|
67
src/lib/arch/x86_64/ports.rs
Normal file
67
src/lib/arch/x86_64/ports.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use core::{arch::asm, num::TryFromIntError};
|
||||
|
||||
pub unsafe fn port_read_u8(port: u16) -> u8 {
|
||||
let result: u8;
|
||||
unsafe {
|
||||
asm! {
|
||||
"in al dx",
|
||||
in("dx") port,
|
||||
out("al") result
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub unsafe fn port_read_u16(port: u16) -> u16 {
|
||||
let result: u16;
|
||||
unsafe {
|
||||
asm! {
|
||||
"in ax dx",
|
||||
in("dx") port,
|
||||
out("ax") result
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub unsafe fn port_read_u32(port: u16) -> u32 {
|
||||
let result: u32;
|
||||
unsafe {
|
||||
asm! {
|
||||
"in eax dx",
|
||||
in("dx") port,
|
||||
out("eax") result
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub unsafe fn port_write_u8(port: u16, data: u8) {
|
||||
unsafe {
|
||||
asm! {
|
||||
"out dx al",
|
||||
in("dx") port,
|
||||
in("al") data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn port_write_u16(port: u16, data: u16) {
|
||||
unsafe {
|
||||
asm! {
|
||||
"out dx ax",
|
||||
in("dx") port,
|
||||
in("ax") data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn port_write_u32(port: u16, data: u32) {
|
||||
unsafe {
|
||||
asm! {
|
||||
"out dx eax",
|
||||
in("dx") port,
|
||||
in("eax") data,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user