Try spawning a process (doesn't work)
Some checks failed
Continuous Integration / Clippy (push) Waiting to run
Continuous Integration / Check (push) Has been cancelled

This commit is contained in:
August 2026-07-02 02:52:52 +00:00
parent c3280cbbfc
commit 7efb4ee901
Signed by: shibedrill
SSH Key Fingerprint: SHA256:M0m3JW1s38BgO2t0fG146Yxd9OJ2IOqkvCAsuRHQ6Pw
9 changed files with 127 additions and 32 deletions

View File

@ -126,7 +126,7 @@ script = '''
cp -f ${LIMINEDIR}/${LIMINEBIN} build/iso/EFI/BOOT cp -f ${LIMINEDIR}/${LIMINEBIN} build/iso/EFI/BOOT
cp -f ${ARTIFACTDIR}/kernel build/iso/boot/${ARCH}/kernel cp -f ${ARTIFACTDIR}/kernel build/iso/boot/${ARCH}/kernel
cp -f ${ARTIFACTDIR}/userboot build/iso/boot/${ARCH}/userboot cargo objcopy --release --bin userboot -- -O binary build/iso/boot/${ARCH}/userboot.bin
xorriso -as mkisofs \ xorriso -as mkisofs \
-b boot/limine/limine-bios-cd.bin \ -b boot/limine/limine-bios-cd.bin \
@ -147,6 +147,11 @@ dependencies = ["iso"]
command = "${QEMUCOMMAND}" 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"]
[tasks.monitor_run]
dependencies = ["iso"]
command = "${QEMUCOMMAND}"
args = ["-display", "none", "-drive", "file=build/gila.iso,format=raw,index=0,media=disk", "-monitor", "stdio"]
[tasks.run] [tasks.run]
dependencies = ["iso"] dependencies = ["iso"]
command = "${QEMUCOMMAND}" command = "${QEMUCOMMAND}"

View File

@ -1,11 +1,32 @@
timeout: 1 timeout: 2
wallpaper: boot():/wallpaper.png wallpaper: boot():/wallpaper.png
wallpaper_style: centered wallpaper_style: centered
default_entry: Gila/Trace
serial: yes
/Gila /+Gila
comment: The Gila microkernel.
//Trace
protocol: limine protocol: limine
kernel_path: boot():/boot/${ARCH}/kernel kernel_path: boot():/boot/${ARCH}/kernel
cmdline: -loglevel=Trace -logdev=display,serial cmdline: -loglevel=Trace -logdev=display,serial
module_path: boot():/boot/${ARCH}/userboot module_path: boot():/boot/${ARCH}/userboot.bin
kaslr: yes
randomize_hhdm_base: yes
//Info
protocol: limine
kernel_path: boot():/boot/${ARCH}/kernel
cmdline: -loglevel=Info -logdev=display,serial
module_path: boot():/boot/${ARCH}/userboot.bin
kaslr: yes
randomize_hhdm_base: yes
//Warn
protocol: limine
kernel_path: boot():/boot/${ARCH}/kernel
cmdline: -loglevel=Warning -logdev=display,serial
module_path: boot():/boot/${ARCH}/userboot.bin
kaslr: yes kaslr: yes
randomize_hhdm_base: yes randomize_hhdm_base: yes

View File

@ -12,6 +12,7 @@ pkgs.mkShell {
rustup rustup
qemu qemu
cargo-make cargo-make
cargo-binutils
]; ];
buildInputs = with pkgs; [ buildInputs = with pkgs; [

View File

@ -5,6 +5,8 @@ use core::arch::asm;
use core::ptr::addr_of_mut; use core::ptr::addr_of_mut;
use intbits::Bits; use intbits::Bits;
use lazy_static::lazy_static;
use x86_64::PrivilegeLevel::{Ring0, Ring3};
use x86_64::structures::gdt; use x86_64::structures::gdt;
use x86_64::structures::gdt::*; use x86_64::structures::gdt::*;
@ -12,6 +14,51 @@ use crate::log::*;
use crate::memory::alloc::format; use crate::memory::alloc::format;
use crate::{log_info, log_trace}; use crate::{log_info, log_trace};
trait ModifyFlags {
fn set_flags(self, flags: DescriptorFlags) -> Self;
}
// All this is necessary because there's no fucking method to change the
// flags in a segment descriptor. WHY??????
impl ModifyFlags for Descriptor {
fn set_flags(self, flags: DescriptorFlags) -> Descriptor {
match self {
Descriptor::UserSegment(a) => {
Descriptor::UserSegment(a.with_bits(52..=55, flags.bits().bits(0..=3)))
}
Descriptor::SystemSegment(a, b) => {
log_trace!("0b{:b}", flags.bits().bits(0..=3));
Descriptor::SystemSegment(a.with_bits(52..=55, flags.bits().bits(0..=3)), b)
}
}
}
}
lazy_static! {
pub static ref TSS: x86_64::structures::tss::TaskStateSegment =
x86_64::structures::tss::TaskStateSegment::new();
pub static ref GDT: x86_64::structures::gdt::GlobalDescriptorTable<64> = {
let mut g = GlobalDescriptorTable::empty();
g.append(Descriptor::kernel_code_segment());
g.append(
Descriptor::kernel_data_segment().set_flags(DescriptorFlags::from_bits_retain(0b1010)),
);
g.append(Descriptor::user_code_segment());
g.append(
Descriptor::user_data_segment().set_flags(DescriptorFlags::from_bits_retain(0b1010)),
);
g.append(
Descriptor::tss_segment(&TSS).set_flags(DescriptorFlags::from_bits_retain(0b1010)),
);
g
};
}
pub const GDT_SELECTOR_KERNEL_CODE: SegmentSelector = SegmentSelector::new(1, Ring0);
pub const GDT_SELECTOR_KERNEL_DATA: SegmentSelector = SegmentSelector::new(2, Ring0);
pub const GDT_SELECTOR_USER_CODE: SegmentSelector = SegmentSelector::new(3, Ring3);
pub const GDT_SELECTOR_USER_DATA: SegmentSelector = SegmentSelector::new(4, Ring3);
pub const GDT_SELECTOR_TSS: SegmentSelector = SegmentSelector::new(5, Ring0);
#[allow(dead_code)] #[allow(dead_code)]
pub trait GdtEntryRead { pub trait GdtEntryRead {
fn base(&self) -> usize; fn base(&self) -> usize;

View File

@ -1,7 +1,7 @@
// Copyright (c) 2025 shibedrill // Copyright (c) 2025 shibedrill
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::log::*; use crate::{SERIAL_3F8, log::*};
use crate::{format, log_error, memory::alloc::string::String}; use crate::{format, log_error, memory::alloc::string::String};
pub fn double_fault(info: String) -> ! { pub fn double_fault(info: String) -> ! {
@ -13,5 +13,6 @@ pub fn page_fault_fatal(addr: usize, info: String) -> ! {
} }
pub fn gen_prot_fault(info: String) { pub fn gen_prot_fault(info: String) {
SERIAL_3F8.lock().log_writeln("Ohhhhh shit double fault");
log_error!("General protection fault: {}", info); log_error!("General protection fault: {}", info);
} }

View File

@ -31,19 +31,22 @@ use limine::firmware::{
FIRMWARE_TYPE_EFI32, FIRMWARE_TYPE_EFI64, FIRMWARE_TYPE_SBI, FIRMWARE_TYPE_X86BIOS, FIRMWARE_TYPE_EFI32, FIRMWARE_TYPE_EFI64, FIRMWARE_TYPE_SBI, FIRMWARE_TYPE_X86BIOS,
}; };
use spin::mutex::Mutex; use spin::mutex::Mutex;
use x86_64::structures::paging::{PageTableFlags, page_table::PageTableEntry}; use x86_64::{
PhysAddr, VirtAddr,
registers::rflags::RFlags,
structures::{
gdt::SegmentSelector,
idt::InterruptStackFrameValue,
paging::{PageTableFlags, page_table::PageTableEntry},
},
};
use crate::{ use crate::{
arch::{ arch::{
asm, asm, x86_64::{
x86_64::{ cpuid::{CPUID, virt_supported}, gdt::{GDT, GDT_SELECTOR_USER_CODE, GDT_SELECTOR_USER_DATA, dump_gdt}, interrupts::get_lapic_addr,
cpuid::{CPUID, virt_supported},
gdt::dump_gdt,
interrupts::get_lapic_addr,
}, },
}, }, boot::modules::MODULE_RESPONSE, memory::paging::{self, active_root_table, map_page, phys_to_virt},
boot::modules::MODULE_RESPONSE,
memory::paging::{self, active_root_table, map_page, phys_to_virt},
}; };
lazy_static! { lazy_static! {
@ -88,8 +91,19 @@ unsafe extern "C" fn main() -> ! {
// Initialize all statics so the bootloader memory can be reclaimed // Initialize all statics so the bootloader memory can be reclaimed
memory::init_statics(); memory::init_statics();
log_info!(
"Long mode: {}",
if asm::long_mode() {
"enabled"
} else {
"disabled"
}
);
// Ensure IDT exists // Ensure IDT exists
IDT.load(); IDT.load();
log_info!("IDT loaded!");
GDT.load();
log_info!("GDT loaded!");
log_info!( log_info!(
"Kernel cmdline: {}", "Kernel cmdline: {}",
@ -188,12 +202,11 @@ unsafe extern "C" fn main() -> ! {
); );
// This is an expensive function. Only run it if we're actually logging the results. // This is an expensive function. Only run it if we're actually logging the results.
let loglevel = LOGGER.lock().level; let loglevel = LOGGER.lock().level;
if loglevel > LogLevel::Trace { if loglevel <= LogLevel::Trace {
paging::walk_tables(); paging::walk_tables();
} }
} }
log_info!("Long mode: {}", asm::long_mode());
dump_gdt(); dump_gdt();
let lapic = get_lapic_addr(); let lapic = get_lapic_addr();
@ -206,18 +219,29 @@ unsafe extern "C" fn main() -> ! {
log_info!("Map status: {:?}", res); log_info!("Map status: {:?}", res);
if let Some(modules_list) = *MODULE_RESPONSE if let Some(modules_list) = *MODULE_RESPONSE
&& modules_list.modules()[0].path().ends_with("/userboot") && modules_list.modules()[0].path().ends_with("/userboot.bin")
{ {
log_info!( let ub = modules_list.modules()[0];
"Found userboot: {} {}", log_info!("Found userboot: {} {}", ub.path(), ub.cmdline());
modules_list.modules()[0].path(), let start_addr = VirtAddr::from_ptr(ub.data() as *const [u8]);
modules_list.modules()[0].cmdline() log_info!("Start address: 0x{:x}", start_addr);
);
log_info!( // This does not work :/
"Start address: 0x{:x}", unsafe {
modules_list.modules()[0].data().as_ptr() as usize InterruptStackFrameValue::new(
); start_addr,
GDT_SELECTOR_USER_CODE,
RFlags::empty(),
phys_to_virt(PhysAddr::new(0x1000)),
GDT_SELECTOR_USER_DATA,
)
.iretq()
};
} }
// TODO:
// - Map APIC
// - Create an interrupt stack frame, push it to stack, and iret to userboot
panic!("Finished boot, but cannot start init because processes not implemented!"); panic!("Finished boot, but cannot start init because processes not implemented!");
} }

View File

@ -5,7 +5,6 @@ const PAGE_SIZE: usize = 4096;
use crate::boot::modules::MODULE_RESPONSE; use crate::boot::modules::MODULE_RESPONSE;
use crate::boot::params::EXECUTABLE_FILE_RESPONSE; use crate::boot::params::EXECUTABLE_FILE_RESPONSE;
use crate::memory::paging::virt_to_phys;
use crate::{LOGGER, LogLevel, format}; use crate::{LOGGER, LogLevel, format};
use alloc::string::String; use alloc::string::String;
@ -13,7 +12,6 @@ use lazy_static::lazy_static;
use limine::request::{ExecutableAddressRequest, HhdmRepsonse, HhdmRequest}; use limine::request::{ExecutableAddressRequest, HhdmRepsonse, HhdmRequest};
use limine::request::{MemmapRequest, MemmapResponse}; use limine::request::{MemmapRequest, MemmapResponse};
use talc::*; use talc::*;
use x86_64::VirtAddr;
pub extern crate alloc; pub extern crate alloc;
@ -90,10 +88,6 @@ pub fn log_address() {
if let Some(resp) = ADDRESS_REQUEST.response() { if let Some(resp) = ADDRESS_REQUEST.response() {
log_info!("Kernel physical start address: 0x{:x}", resp.physical_base); log_info!("Kernel physical start address: 0x{:x}", resp.physical_base);
log_info!("Kernel virtual start address: 0x{:x}", resp.virtual_base); log_info!("Kernel virtual start address: 0x{:x}", resp.virtual_base);
log_info!("Testing virt_to_phys(): 0x{:x}", resp.virtual_base);
let hhdm_vaddr = VirtAddr::new(resp.virtual_base);
let hhdm_paddr = virt_to_phys(hhdm_vaddr);
log_info!("Result: 0x{:x}", hhdm_paddr.unwrap());
} else { } else {
log_warning!("No kernel address response provided."); log_warning!("No kernel address response provided.");
} }

View File

@ -144,6 +144,7 @@ pub fn phys_to_virt(phys: PhysAddr) -> VirtAddr {
VirtAddr::new(phys.as_u64() + HHDM_RESPONSE.offset) VirtAddr::new(phys.as_u64() + HHDM_RESPONSE.offset)
} }
#[allow(dead_code)]
pub fn virt_to_phys(virt: VirtAddr) -> Option<PhysAddr> { pub fn virt_to_phys(virt: VirtAddr) -> Option<PhysAddr> {
let root_table = unsafe { active_root_table() }; let root_table = unsafe { active_root_table() };
let mut current_table = root_table; let mut current_table = root_table;

View File

@ -5,6 +5,7 @@ use core::panic::PanicInfo;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
unsafe extern "C" fn main() -> ! { unsafe extern "C" fn main() -> ! {
unsafe { x86_64::instructions::port::Port::new(0x3f8).write(9u8) };
panic!() panic!()
} }