15

I am getting started with a minimal OS kernel (just gdt and place holder idt). Using i386 assembly and freestanding C. I wanted to change the position of the cursor for which i found several sites giving the following.

void set_cursor_position(uint16_t row, uint16_t col) {
    uint16_t pos = row * 80 + col;

    // low byte
    outb(0x3D4, 0x0F);
    outb(0x3D5, pos & 0xFF);

    // high byte
    outb(0x3D4, 0x0E);
    outb(0x3D5, (pos >> 8) & 0xFF);
} 

Then for the outb function I found:

static inline void outb(uint16_t port, uint8_t val) {
    __asm__ volatile ("out %0, %1" : : "a"(val), "Nd"(port) : "memory");
}

However when i try to use the this the Qemu screen started flickering (the default text on the screen kept flickering). Just clearing the screen happens without a problem.

void clear_screen(void) {
    volatile char *vidptr = (char*)0xb8000;
    for (int i = 0; i < 80 * 25 * 2; i += 2) {
        vidptr[i] = ' ';
        vidptr[i + 1] = 0x07;  // Light gray on black
    }
}

Given the kernel main function:

void kernel_main(void) {
    init_idt();
    clear_screen();
    while(1);
}

Using GDB I am able to trace to the while(1), however now if I do:

void kernel_main(void) {
    init_idt();
    clear_screen();
    set_cursor_position(0, 0);
    while(1);
}

GDB can't seem to be able to even hit tbreak clear_screen, the bt giving some random address, further using info registers in Qemu I found that even the IDT base and limit aren't set properly (they were without this line I checked). It's not just the usage of set_cursor_position any line with outb called causes this for example:

void kernel_main(void) {
    init_idt();
    clear_screen();

    outb(0x3D4, 0x01);
    uint8_t width = inb(0x3D5) + 1;
    while(1);
}

The following are the build commands if they are of any help:

mkdir -p build
mkdir -p build/inter
nasm -f bin -I src/ src/bootloader.asm -o build/inter/bootloader.bin
nasm -f elf32 src/isr.asm -o build/inter/isr.o
gcc -m32 -ffreestanding -g -nostdlib -fno-stack-protector -O0 -fno-omit-frame-pointer -ffunction-sections -fdata-sections -Wall -Wextra -c src/idt.c -o build/inter/idt.o
nasm -f elf32 src/start_protected.asm -o build/inter/start_protected.o
gcc -m32 -ffreestanding -g -nostdlib -O0 -Wall -Wextra -c src/kernel.c -o build/inter/kernel.o
ld -m elf_i386 -T linker.ld -o build/inter/second_stage.elf build/inter/start_protected.o build/inter/kernel.o build/inter/idt.o build/inter/isr.o
ld: warning: build/inter/second_stage.elf has a LOAD segment with RWX permissions
objcopy -O binary build/inter/second_stage.elf build/inter/second_stage.bin
dd if=/dev/zero of=build/disk.img bs=512 count=2880
2880+0 records in
2880+0 records out
1474560 bytes (1.5 MB, 1.4 MiB) copied, 0.0238469 s, 61.8 MB/s
dd if=build/inter/bootloader.bin of=build/disk.img conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000140471 s, 3.6 MB/s
dd if=build/inter/second_stage.bin of=build/disk.img bs=512 seek=1 conv=notrunc
1+1 records in
1+1 records out
992 bytes copied, 0.000108903 s, 9.1 MB/s
qemu-system-i386 -drive format=raw,file=build/disk.img

I am not sure how to fix this or even debug it. Any guidance is appreciated.

3
  • 3
    It is likely the root of you problem is in what isn't been shown. This isn't a minimal reproducible example, but if you created a github project with all your code and support/build files I could take a look. It sounds like you are triple faulting and the flashing text might be the continuous reboots. If using QEMU run it with the -d int -M smm=off -no-shutdown -no-reboot the exception dump may be useful in determining what happened. You could add that output to your question along with contents of your linker.ld and the start_protected.asm Commented Oct 1 at 16:29
  • 3
    You were correct the problem was in start_protected.asm, I went through its hexdump and noticed it was taking 896 bytes. Further in bootloader.asm I had set number of sectors to read (in AL) as 1 however the 896 bytes was clearly larger, so i changed the number of sectors to 2, and then padded to 1024. I think the addition of the set cursor position made the size of the second stage pass 1 sector thus causing the problem. Apologies for the oversight. Commented Oct 2 at 3:44
  • 2
    You might find it helpful to use grub or similar as a bootloader instead of rolling your own - I ended up with similar issues as my kernel size increased due to simplifiying assumptions I had made while loading elf from a FAT filesystem in 16-bit asm. Some useful links if you choose this route: wiki.osdev.org/Multiboot wiki.osdev.org/GRUB#Using_GRUB_to_boot_your_OS Commented Oct 2 at 10:20

1 Answer 1

8

I usually find bochs to be easier for debugging this low-level stuff, it's got a good integrated assembly language debugger and you can enable trace logging for the various emulated subsystems which could well give you a window into what the vga controller is seeing.

First, though, I'd start by using objdump to disassemble the code from your program - specifically the set_cursor_position function and calls through outb to check what exactly it has assembled. You need the port number in dx and the data in al, which it looks like you do.

I'd double check all of the port assignments - this is a good resource for starters: https://wiki.osdev.org/VGA_Hardware#Port_0x3C4,\_0x3CE,\_0x3D4

Specifically, 0x3D4 is an index register but it can be remapped to 0x3B4 depending on the overall state - you might want to check that. You might also want to check if there are any timing requirements - an idle time for the "hardware" to lock the values due to the CPU running faster than the bus, or if you need to set the bytes the other way around.

This page: http://www.osdever.net/FreeVGA/vga/crtcreg.htm gives some good background on the registers and this page http://www.osdever.net/FreeVGA/vga/textcur.htm gives an overview of the "quirks" to expect in the interface

Good luck!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.