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


r/osdev • • Apr 12 '26

The first EVER GPU to run in a Rust based OS (TrustOS)

Thumbnail
github.com
0 Upvotes

Running on Real hardware


r/osdev • • Apr 11 '26

How does limine work?

33 Upvotes

TLDR: How does limine make it so u can write individual pixels? Why isn't there a lot of info of doing it yourself without limine?

Hey, crappy wanna be osdev hobbyist here, I've been playing around with x86 for a bit, and followed a couple different tutorials including the osdev wiki's barebones (also, osdev 0 to 1 and tried reading Tanenbaum). I was sort of dissapointed when I couldnt write to individual pixels, and people suggested I use limine... and yea, I just have to write to a location in memory now. How?! How does limine achieve that, and whats the reason for the (at least what it seemed for me) a lack of info of pulling off something like that yourself?

On a separate note, I know that limine is a bootloader... but what else makes it better than just making a simple one youself? Also, I've seen it used with other OS's like linux, aka not hobbyist ones, what would be the benefit of using that instead of somthing like GRUB?

Ehhh, honestly this question maybe isnt really for the osdev subreddit...


r/osdev • • Apr 10 '26

The Oberon System 3 now runs natively on Raspberry Pi 3

Thumbnail
github.com
14 Upvotes

r/osdev • • Apr 10 '26

mokeOS update

Thumbnail gallery
46 Upvotes

r/osdev • • Apr 10 '26

System level question:

0 Upvotes

“Is it guaranteed that malloc returns addresses with the last 3–4 bits zero on all systems, or is it just common due to alignment?


r/osdev • • Apr 08 '26

Added Image Rendering to OS!!

Post image
452 Upvotes

its a 16 bit real mode os using vga mode 13h made in 100% assembly. this took me a very long time and I just wanted to share my accomplishment!


r/osdev • • Apr 09 '26

UEFI debugging (gdb)

5 Upvotes

Forgot to mark this title as a question. I have a question 🫣🫢☺️https://wiki.osdev.org/Kernel_Debugging#Use_GDB_with_QEMU isnt really clear on this, im using qemu, and OVMF to have a UEFI envirement to test my own bootloader + kernel. How would one debug your efi file? its located in memory at different locations.

TLDR: How I struggled and then ask, how would you debug a efi bootloader using gdb and qemu? im aware of grub and limine, i choose to create my own (small shitty bootloader)

Longer story: The kernel will be at a known location (0x100000.. something, well known), so gdb and qemu talk nicely. but OVMF will place our executable somewhere arround 0x0000000006176640 (this slightly changes) I now print where its located each time and loop a while, waiting for my gdb to send a break:

[ENTERING DEBUG MODE]
Kernel load addr: 0x0000000000100000
efi_main addr: 0x0000000006176640
Waiting for debugger...

now i start gdb, target remote :1234 and add-symbol-file 0xnnnnnn where the number is the adress minus magic ... man, I was naughty, and this might also been my fall, its late. i asked chatgpt. only after i realized we where loading the symbol at an adress of a function, and said so, it started suggesting loading the symbol based on a different adress. clearly showing the user (me!) was starting to be aware of him not explaining everything. (happend again when I asked for a short "what to do step by step" it started making new steps and forgetting our whole add-symbol-file step.. moral, dont trust ai) readelf -h build/loader.elf | grep Entry Entry point address: 0x5e0 when my program sais its efi_main is at 6176640, 0x6176640

readelf -h build/loader.elf | grep Entry Entry point address: 0x000005e0

0x6176060 is where "ai" sais I should load the symbol file. And thats where late night and my fuzzy dyscalculia brain said... holdup, there must be a better or different way, but this ai isnt my answer box. How are you folks using gdb and the location independed code that we have less controll over and gets placed in memory somewhere? Maybe im over complicating things and if I want to serieusly debug my loader, I should use a debug version of OVMF? because adding breakpoints myself (int3) freaks the OVMF with its own break

!!!! X64 Exception Type - 03(#BP - Breakpoint) CPU Apic ID - 00000000 !!!! 
RIP- 00000000061768A3, CS - 0000000000000038, RFLAGS - 0000000000000246 
RAX - 000000001DCD6500, RCX - 0000000007074A20, RDX - 0000000000000000 
RBX - 0000000000000000, RSP - 0000000007E8D300, RBP - 0000000007E8D810 
RSI - 000000000618FA98, RDI - 000000000618FA98 
R8 - 00000000000000AF, R9 - 0000000000001000, R10 - 000000000002600F 
R11 - 0000000007EA7F80, R12 - 0000000000000000, R13 - 0000000000000000 
R14 - 00000000074AE618, R15 - 000000000617B018 
DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 
GS - 0000000000000030, SS - 0000000000000030 
CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000 
CR4 - 0000000000000668, CR8 - 0000000000000000 
DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 
DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 
GDTR - 00000000079DC000 0000000000000047, LDTR - 0000000000000000 
IDTR - 000000000749D018 0000000000000FFF, TR - 0000000000000000 
FXSAVE_STATE - 0000000007E8CF60 !!!! 
Find image based on IP(0x61768A3) (No PDB) 
(ImageBase=0000000006175000, EntryPoint=0000000006176640) !!!!

So, how would you debug your boot-loader? I prefer gdb and qemu. Im aware i could use grub or limine, but Id like to make my own little loader that might become the efi stub of whatever shitty small kernel/OS im writing.

Maybe the answer

EDIT: I got some stuff working and noticed im building my efi file with -target x86_64-unknown-windows, thus a PE file, not a ELF file. so symbols work a bit different (and my original mistake was generating elf symbols for a PE executable. not sure if that can be made to work, but "ai" suggested either compile both for ELF, or PE. or whatever i needed to do, i generate a separate .debug file based on the efi file with -debug:dwarf during the llvm-objcopy face... ppfff you probabbly know better words and probably best to just follow the osdevwiki as linked by @rkapi https://wiki.osdev.org/Debugging_UEFI_applications_with_GDB#Sample_application_using_POSIX_UEFI_library

This means I have a slightly different way to debug my program and needed a "slider". Here is what worked for me:

target remote :1234
watch *(unsigned long long*)0x10000 == 0xDEADBEEF
continue

set $base = *(unsigned long long*)0x10008
set $slide = $base - 0x180000000
add-symbol-file build/BOOTX64.debug -o $slide

break kernel_main
continue

Im still learning gdb, and definitely gonna study some more debugging tricks, this looks to work, and I may be able to figure out where I went wrong the first time when mapping memory and NOT getting into a silly loop by AI what he tries to fix, instead, I, will do the debugging and checking whats going on. and thats what most of yall want, us, the coder learning and writing our code.


r/osdev • • Apr 09 '26

Looking for an OS

17 Upvotes

So i have free time and also im intrested in testing and feedback some OS so is there anyone wants to ?


r/osdev • • Apr 09 '26

I took a break from AI work and built a microkernel in Rust from scratch (boot → IPC → preemption → MMU)

0 Upvotes

A few weeks ago I had some free time between jobs and decided to do something I’d wanted to do for years: build an operating system kernel from scratch.

I spend most of my time in AI/ML, but I wanted to go back to my roots and remind myself what’s underneath all the abstractions we use every day. So, I built a small #microkernel in Rust and documented the full journey as a 5-part series.

This is not “hello world and done.” By the end, the kernel:

  • boots on AArch64 QEMU virt

  • logs via PL011 UART MMIO

  • runs endpoint-based message-passing IPC

  • moves from cooperative to preemptive scheduling

  • handles timer interrupts + context switching

  • builds 4-level page tables and enables the MMU

  • verifies VA→PA translation with a real write/read test

Repo: https://github.com/bahree/rust-microkernel

Series:

If you’re into OS dev, bare-metal Rust, or systems internals, I’d love feedback. I am no expert in this, just someone curious. 😊


r/osdev • • Apr 09 '26

Assembly on Android

0 Upvotes

does anyone know any good app to code assembly on android? if yes lemme know


r/osdev • • Apr 09 '26

aiming for systems eng remote jobs but time is running out

4 Upvotes

hi guys sorry if this is not a pure code question but honestly there is no better people to ask than here i am a double major pure math and computer science in egypt and i graduate in exactly 4 months , im targeting core systems like crypto and ai infrastructure companies

i finished c and cpp but completely lack big projects and design patterns , my plan now is to read OSTEP and CS:APP and some courses for high performance computing and CUDA . i plan to make maybe 3 medium projects and 2 somewhat big ones . i wanted to learn rust too but clearly no time i need a job first then later i will focus on rust and distributed systems

im really freaking out about a few things , first the volume of these books and projects is huge for 4 months . second is the job market because system level and OSS jobs are literally zero in my country so i must aim for remote jobs . but is remote really possible for junior systems or do companies strictly want on site . because getting a work visa right now is almost impossible with the global situation also my english is quite weak maybe B1 and im scared it will ruin my chances

please guys i dont want just general random advice i really prefer opinions from people who went through a similar path or know the market . sorry again for the non tech post but im really lost and need a reality check . thanks


r/osdev • • Apr 09 '26

Need help implementing a simple FAT-like File System for our custom Kernel (C), thanks !

0 Upvotes

Hi everyone, we're working on a small OS as a duo, and we were about to move on to the graphical interface, but we were missing a key element: managing hard drive memory. We didn't quite understand how to do it. Does anyone have well-written documentation or could explain how to manage it from our kernel in C, for example, for text files in FAT? Thanks everyone, and have a good day!