Ian Channer
Ian Channer

Reputation: 21

Qemu emulator flickers when entering protected mode for custom bootloader

Currently I'm having a hard time with my bootloader after I enter protected mode by setting the lsb in register cr0 to 1. I perform a far jump to the kernel code segment as defined by jmp 0x8:start_kernel. I use 0x8 because my kernel code starts at the 8th byte offset in my GDT, resetting the code segment (register cs). And then I set the other segment registers to 0x10 (16th byte offset ~ the kernel data segment selector as defined by the GDT). I re-enable interruptions (sti) and call the kernel_main (kernel entry point). After going into protected mode the Qemu emulator flickers uncontrollably and the output from the kernel is not produced. Any help would be appreciated thank you!

boot.asm:

[bits 16]
extern kernel_main
global start_kernel



xor ax, ax
mov es, ax
mov ds, ax
mov bp, 0x8000
mov sp, bp

mov dl, 0x80 ; first hard disk
mov ah, 0x02 ; int 0x13 function number
mov al, 0x05 ; kernel is only 512 bytes (# sector's we have to read) 
mov ch, 0x00 ; cylinder number 
mov cl, 0x02 ; #starting sector (starts from 1 not 0) first 512 bytes for boot loader
mov dh, 0x00 ; head number  
mov bx, 0x7e00 ; code for bootloader starts at 7c00 ~ 31744 bytes + 512 bytes (for bootlaoder) = 7E00

int 0x13 

lgdt [gdtr]

mov ah, 0x0 ; service for setting the video mode
mov al, 0x03 ; setting video mode to be text mode w/ 16 colors
int 0x10

cli 

mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x08:start_kernel

[bits 32]
start_kernel:

    mov eax, 0x10
    mov ss,  eax
    mov ds,  eax
    mov fs,  eax
    mov gs,  eax
    mov es,  eax
    sti
    call kernel_main


gdt:
    null_descriptor: db 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
    kernel_code: db 0x0, 0xCF, 0x9A, 0x0, 0x0, 0x0, 0xFF, 0xFF
    kernel_data: db 0x0, 0xCF, 0x92, 0x0, 0x0, 0x0, 0xFF, 0xFF
    user_code: db 0x0, 0xCF, 0xFC, 0x0, 0x0, 0x0, 0xFF, 0xFF
    user_data: db 0x0, 0xCF, 0xF2, 0x0, 0x0, 0x0, 0xFF, 0xFF
gdt_end:

gdtr:
    size: dw gdt_end - gdt - 1
    base: dd gdt

times 510-($-$$) db 0
db 0x55, 0xaa

makefile:

ASM=nasm
CC=x86_64-elf-gcc
BOOTLOADER=boot.asm
BOOTLOADER_BIN=boot.o
KERNEL=kernel.c 
KERNEL_FLAGS= -Wall -m32 -ffreestanding -fno-asynchronous-unwind-tables -fno-pie -c
KERNEL_OBJECT= kernel.o
KERNEL_IMG=kernel.img
LINKER_FILE=linker.ld
OUTPUT_BIN=kernel.bin

build: $(BOOTLOADER) $(KERNEL)

    $(ASM) -f elf32 $(BOOTLOADER) -o $(BOOTLOADER_BIN)
    $(CC) $(KERNEL_FLAGS) $(KERNEL) -o $(KERNEL_OBJECT) 
    x86_64-elf-ld -melf_i386 -T$(LINKER_FILE) $(BOOTLOADER_BIN) $(KERNEL_OBJECT) -o linked_kernel.elf
    x86_64-elf-objcopy -O binary linked_kernel.elf $(OUTPUT_BIN)
    dd if=$(OUTPUT_BIN) of=$(KERNEL_IMG) conv=notrunc
    qemu-system-x86_64 -s kernel.img
clean:
    rm -f $(BOOTLOADER_BIN) $(KERNEL_OBJECT) $(OUTPUT_ELF) $(OUTPUT_BIN) $(KERNEL_IMG)

kernel.c:

volatile unsigned char* video = (volatile unsigned char*)0xB8000;

void kernel_main() {
    // Write 'H' and 'i' at the top-left of the screen.
    video[0] = 'H'; // Character 'H'
    video[1] = 0x04; // Attribute byte (light gray on black)
    video[2] = 'i'; // Character 'i'
    video[3] = 0x04; // Attribute byte (light gray on black)

    // Infinite loop to keep the kernel running
    while (1);
}

Information regarding GDT table:

gdt = '''
[
    {   "name": "null_descriptor", "type": "null" },
    
    {   "name": "kernel_code", "base_address": "0", 
        "limit": "fffff", "granularity": "4kb", 
        "system_segment": false, "type": "code", 
        "accessed": false, "read_enabled": true, "conforming": false,
        "privilege_level": 0, "present": true, "operation_size": "32bit", "64bit": false  },
        
    {   "name": "kernel_data", "base_address": "0", 
        "limit": "fffff", "granularity": "4kb", 
        "system_segment": false, "type": "data", 
        "accessed": false, "expands": "up", "write_enabled": true,
        "privilege_level": 0, "present": true, "upper_bound": "4gb", "64bit": false  },
        
    {   "name": "userspace_code", "base_address": "0", 
        "limit": "fffff", "granularity": "4kb", 
        "system_segment": false, "type": "code", 
        "accessed": false, "read_enabled": true, "conforming": false,
        "privilege_level": 3, "present": true, "operation_size": "32bit", "64bit": false  },
        
    {   "name": "userspace_data", "base_address": "0", 
        "limit": "fffff", "granularity": "4kb", 
        "system_segment": false, "type": "data", 
        "accessed": false, "expands": "up", "write_enabled": true,
        "privilege_level": 3, "present": true, "upper_bound": "4gb", "64bit": false  }
]
''';

Upvotes: 1

Views: 71

Answers (0)

Related Questions