Reputation: 21
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