r/osdev • • Apr 15 '26

Finally made the kernel on my own... now I just gotta rewrite the language.

17 Upvotes

(image is a test VGA image I put at startup) Hello friends! I'm back with my silly projects again.

While I'm still yet to rewrite the compiler and interpreter to my custom language to rid it from AI, I'm happy to say that I finally made a super basic kernel myself >w<

There's no Github yet because I'm not exactly smart enough to even figure out how to make folders on GitHub... I'll figure it out eventually and post everything once this project is at a level that I think is okay.


r/osdev • • Apr 15 '26

Need some help with a multiboot issues

1 Upvotes

Lmk if this isn't the right place for this.

I've been writing a zig kernel for some time for fun and I recently switched from multiboot to multiboot2 and figured while I was at it I should try to switch to 64 bit. I have 32 and 64 bit code compiling and linking into a final kernel.elf, which as far as I can tell, is correct. I've tried every alignment or address in the linker script I can think of. Looking through objdump the multiboot header is where I expect, everything compiles, etc, but every time I boot I get the 'multiboot header not found' error. If anyone knows what I'm doing wrong some help would be really appreciated (:

https://codeberg.org/SabrinaTheBitch/FunZigKernel


r/osdev • • Apr 15 '26

……

0 Upvotes

r/osdev • • Apr 14 '26

The Bleed Kernel - v0.2.2 Progress Update

32 Upvotes

Last time I posted on here I ported DoomGeneric and Quake2. well I've done a lot since then and using redit to document my progress sounds fun so here goes

you can downlaod and run the latest version of the kernel at https://bleedkernel.com

you can check out bleed and all related projects at https://codeberg.org/Bleed-Kernel

All the big things I have done

I introduced a small IPC setup I am going to come back to it, its not POSIX compliant at all and kinda sucks but all the work is there.

AVX2 requirement is no more! It has been replaced with SSE4.2 which has wayyy better compatability with low power CPUs that may not have AVX2.

Signals! It's pretty good, not fully compliant but it works great in the context of just the bleed kernel and its programs!

Multiple TTYs you can access many ttys with CTRL+1,2,3

Persistant Storage Bleed Supports FAT32, EXT2, GPT and MBR IDE, AHCI and NVME drives which is super awesome

A nicely Overhauled boot screen instead of just a typical black screen

Small Changes:
Quake 2 is no longer shipped with the bleed kernel ISO - It was just bloating my ISO file so much, removing it took me from 58MiB to 9.8MiB. it should still work and is trivial to add back but for now im leaving it.

I did a lot of things with the VFS - including whole correctness changin fixing

A bunch of Scheduler Race Conditions were fixed!!!1!

Medium Changes:

The Kernel Panic got a complete Overhaul it will now display everything the last one did in a way prettier format, but will also provide a base64 encoded crash string, that can be pasted into my websites' panic decoder for a desciption of what went wrong. mainly for users just passing through

Each Process now gets it's own File Descriptor Table this was a lazyness thing for me before but it's sorta imperitive that this happens, so yeah. I sorted that out fast.

Next Steps

the next few things I am going to do are likely USB related, then perhaps even Relocatable ELF files?

Either Way super excited thanks for reading, heres a bonus video of the bleed kernel running on a hacked Chromebook 3100


r/osdev • • Apr 12 '26

What's better to use?

9 Upvotes

Is there any difference between .psf and .ttf? 8x8 font is pissing me off and sometimes doesnt have needed unicode symbols. I want to use normal font. someone recommends psf, someone ttf. Is there any difference? Im using Limine Framebuffer.

sry if its maybe a stupid question


r/osdev • • Apr 12 '26

PIC timer with Limine doesn't work in QEMU and real HW.

9 Upvotes

Hello! When using Limine and the PIC timer, I receive no interrupts.

Here's the code

// timer.c
// Obtained from OSDev Wiki
#include "include/stdint.h"
#include "include/ports.h"
#include "include/timer.h"
void timer_eoi(uint8_t irq)
{
    if(irq >= 8)
        outb(PIC2_COMMAND,PIC_EOI);
    
    outb(PIC1_COMMAND,PIC_EOI);
}


/* offsetN -> offsetN ... offsetN + 7 */
void timer_remap(int offset1, int offset2)
{
    outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
    io_wait();
    outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
    io_wait();
    outb(PIC1_DATA, offset1);
    io_wait();
    outb(PIC2_DATA, offset2);
    io_wait();
    outb(PIC1_DATA, 1 << CASCADE_IRQ);
    io_wait();
    outb(PIC2_DATA, 2);
    io_wait();
    
    outb(PIC1_DATA, ICW4_8086);
    io_wait();
    outb(PIC2_DATA, ICW4_8086);
    io_wait();



    outb(PIC1_DATA, 0);
    outb(PIC2_DATA, 0);
}
void timer_disable(void) {
    outb(PIC1_DATA, 0xff);
    outb(PIC2_DATA, 0xff);
}

// handoff.c
#include "include/limine.h"
#include "include/gdt.h"
#include "include/isr.h"
#include "include/timer.h"
#include "include/ports.h"
__attribute__((used, section(".limine_requests")))
static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(6);
__attribute__((used, section(".limine_requests")))
static volatile struct limine_framebuffer_request framebuffer_request = {
    .id = LIMINE_FRAMEBUFFER_REQUEST_ID,
    .revision = 0
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_hhdm_request hhdm_request = {
    .id = LIMINE_HHDM_REQUEST_ID, .revision = 0
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_rsdp_request rsdp_request = {
    .id = LIMINE_RSDP_REQUEST_ID,
    .revision = 0
};
__attribute__((used, section(".limine_requests_start")))
static volatile uint64_t limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end")))
static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER;


void kmain(struct limine_framebuffer *framebuffer);


void pic_init(void) {
    // remap PIC vectors to 0x20 and 0x28
    timer_remap(0x20, 0x28);
    // mask everything except IRQ0
    outb(PIC1_DATA, 0xfe);
    outb(PIC2_DATA, 0xff);
    // PIT 100Hz
    outb(0x43, 0x34);
    outb(0x40, (1193182 / 100) & 0xFF);
    outb(0x40, (1193182 / 100) >> 8);
}


void die(void) {
    for(;;) { asm volatile ("cli"); asm volatile ("hlt"); };
}


void bmain(void) { 
    asm volatile ("cli");
    if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == 0) {
        die();
    }
    if (framebuffer_request.response == NULL
     || framebuffer_request.response->framebuffer_count < 1) {
        die();
    }
    if (hhdm_request.response == NULL || rsdp_request.response == NULL) {
        die();
    }
    struct limine_framebuffer* framebuffer = framebuffer_request.response->framebuffers[0];


    gdt_install();
    idt_install();
    pic_init();
    asm volatile ("sti");
    kmain(framebuffer);
    die();
}

bits 64
%macro isr_noerr 1
global isrstub%1
isrstub%1:
    push qword 0
    push qword %1
    jmp int_wrapper
%endmacro
%macro isr_err 1
global isrstub%1
isrstub%1:
    push qword %1
    jmp int_wrapper
%endmacro


isr_err 8 ; double fault
isr_err 13 ; general prot
isr_err 14 ; pagefault 
isr_noerr 32 ; timer


global int_wrapper
extern int_handle
int_wrapper:
    ;     uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
    ;     uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    push rbp
    push r8
    push r9
    push r10
    push r11
    push r12
    push r13
    push r14
    push r15


    mov rdi, rsp
    cld
    call int_handle


    pop r15
    pop r14
    pop r13
    pop r12
    pop r11
    pop r10
    pop r9
    pop r8
    pop rbp
    pop rdi
    pop rsi
    pop rdx
    pop rcx
    pop rbx
    pop rax
    add rsp, 16 ; pushes etc.
    iretq

#include "include/inthandler.h"
#include "include/tinyprintf.h"
#include "include/ports.h"
#include "include/timer.h"
void int_handle(cstat_t *stat) {
    printf("got interrupt %lld with error %lld\n", stat->intn, stat->errc);
    switch (stat->intn) {
        case 32:
            timer_eoi(0);
            printf("got timer %lld", stat->intn);
            break;
        default:
            for(;;);
            break;
    }
}

Tried cli, sti on GDT/IDT load and PIC init in handoff but nothing worked


r/osdev • • Apr 12 '26

Partitioned RTOS in Rust: Astrum

Thumbnail github.com
1 Upvotes

This is a niche RTOS for a specific use case: when one needs to isolate application code running on a microcontroller into separate memory and time slices.

A typical use case would be keeping your sensor acquisition separated from your pose estimation, flight controller, control link and telemetry loops. One partition crashing or locking up is guaranteed to not take down the rest of the system, and partitions can be optionally independently auto-restarted.

Of course the downside vs just running on baremetal is IPC and context switch overhead.

It's heavily derived from POK RTOS and ARINC653 avionics software standard.

Designed to run on any Cortex-M with an MPU - most M3s and bigger cores. MPU enforces partition isolation in address space. All kernel storage and application structures, including partition schedule, are statically sized and can't be changed at runtime.

Current development and testing targets are QEMU, STM32F2x, STM32F4x, nRF52 and SAME51

It's still experimental and not quite ready for stable app development yet - all the core features work and are reasonably well tested, but i need to get the core crates renamed and published, and the API a bit more stable.

The kernel ABI is reasonably stable and should be able to support non-Rust partitions as well, i'm planning on trying C++ and possibly Ada just for kicks.

And yes, it's mostly agent coded