Kernel stops executing after adding keyboard-related code, even if unused

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
latorche
Posts: 1
Joined: Tue Jul 29, 2025 7:46 am
Libera.chat IRC: #1942

Kernel stops executing after adding keyboard-related code, even if unused

Post by latorche »

I'm writing a small OS with a 16-bit bootloader and a 32-bit kernel in C.
Everything worked fine with just screen-related code.

But as soon as I add the keyboard-related files (IDT setup, IRQs, keyboard handler…), the kernel stops working — even if none of the functions are called.

Simply compiling those files seems to break everything.
If I remove them, it works again.

Could this be a linker issue, memory alignment problem, or corrupted binary?
Is it possible that unused globals or sections shift _start or break execution?

GitHub:
👉 https://github.com/arnaudderison/picos
User avatar
iansjack
Member
Member
Posts: 4908
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Kernel stops executing after adding keyboard-related code, even if unused

Post by iansjack »

This normally means that you are not loading the whole kernel. Are you sure you are loading enough sectors?
MichaelPetch
Member
Member
Posts: 857
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Kernel stops executing after adding keyboard-related code, even if unused

Post by MichaelPetch »

A quick glance at your Makefile and linker.ld file suggest one potential problem that could produce the results you are seeing. You have a kernel_entry.asm file that gets compiled to kernel_entry.o . Since you are jumping to 0x00001000 in your bootloader you need to ensure the code in kernel_entry.o appears first in kernel.bin. Often this is done in the Makefile by specifying kernel_entry.o first before other .o files. Your makefile however doesn't guarantee any order that the object files are linked as it is whatever order the file system and `make` returns. Likely kernel_entry.o isn't first. Some other code from another .o is appearing first.

One quick way of testing this is to modify the linker.ld script to place the `.text` section of kernel_entry.o first before all other code. Try testing with something like:

Code: Select all

ENTRY(_start)

SECTIONS {
  . = 0x1000;

  .text : {
    build/kernel/kernel_entry.o(.text)
    *(.text)
  }

  .data : {
    *(.data)
  }

  .bss : {
    *(.bss COMMON)
  }
  rodata : {
    *(.rodata*)
    }
}
Another option is to list kernel_entry.o first during linking with something like this change to your Makefile:

Code: Select all

kernel.bin: $(OBJ_ASM) $(OBJ_S) $(OBJ_C) linker.ld
        $(LD) $(LDFLAGS) -o $@ $(BUILD_DIR)/kernel_entry.o $(OBJ_ASM) $(OBJ_S) $(OBJ_C)
        $(OBJCOPY) -O binary $@ $@
This works even though kernel_entry.o will appear twice on the linker command line. LD will not generate duplicate code and data when encountering the same object more than once.

`ENTRY` in the linker script doesn't apply to BINary executables. The metadata is stripped out of the binary including the entry point. This leaves you needing to make sure that the kernel bootstrap code appears first in the resulting binary file.
Post Reply