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.
-d int -M smm=off -no-shutdown -no-rebootthe exception dump may be useful in determining what happened. You could add that output to your question along with contents of yourlinker.ldand thestart_protected.asmstart_protected.asm, I went through itshexdumpand noticed it was taking896bytes. Further inbootloader.asmI had set number of sectors to read (inAL) 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.