I'm writing a simple OS. I'm having trouble with the output string in qemu screen, the output of the kernel.c
file doesn't show on the qemu screen):
I have the following code:
bootloader.asm
BITS 16
org 0x7C00
start:
; Load the kernel from disk into memory
mov ax, 0x1000
mov es, ax
mov bx, 0x0000
mov ah, 0x02
mov al, 3
mov ch, 0
mov cl, 2
mov dh, 0
int 0x13
; Set up protected mode
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_SEG:init_pm
[BITS 32]
init_pm:
; Setup segment registers
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Jump to the kernel entry point
call kernel_main
hang:
hlt
jmp hang
gdt:
dw 0, 0, 0, 0 ; null descriptor
dw 0xFFFF, 0, 0x9A00, 0x00CF ; code segment
dw 0xFFFF, 0, 0x9200, 0x00CF ; data segment
gdt_descriptor:
dw gdt - gdt_descriptor - 1
dd gdt
CODE_SEG equ gdt - gdt_descriptor + 8
DATA_SEG equ gdt - gdt_descriptor + 16
kernel_main equ 0x00100000
times 510-($-$$) db 0
dw 0xAA55
kernel.c
void kernel_main() {
char* video_memory = (char*)0xB8000;
*video_memory = 'A';
}
linker.ld
ENTRY(kernel_main)
SECTIONS
{
. = 0x00100000;
.text :
{
*(.text)
}
.rodata :
{
*(.rodata)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
Makefile
# Makefile
CC = gcc
LD = ld
NASM = nasm
CFLAGS = -m32 -ffreestanding -fno-pie -fno-stack-protector -Wall -Wextra
LDFLAGS = -m elf_i386
all: os-image.bin
os-image.bin: bootloader.bin kernel.bin
cat $^ > $@
bootloader.bin: bootloader.asm
$(NASM) -f bin -o $@ $<
kernel.bin: kernel.o
$(LD) $(LDFLAGS) -T linker.ld -o $@ $<
kernel.o: kernel.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *.bin *.o os-image.bin
The output seems that the kernel.c
file is not running, so how to solve this problem?
In the kernel.c
file a kernel_entry.asm
can be added, which will specify the kernel entry function and call the entry function. Then link the kernel_entry.asm
file and kernel.c
file.
You may not need it in following codes, but you should keep the entry function at the top in the kernel.c
file.
By the following codes, it works:
boot.asm
BITS 16
org 0x7C00
start:
mov bp, 0x9000
mov sp, bp
; Load the kernel from disk into memory
mov bx, 0x1000
mov ah, 0x02
mov al, 3
mov ch, 0
mov cl, 2
mov dh, 0
int 0x13
; Set up protected mode
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp 0x08:init_pm
[BITS 32]
init_pm:
; Setup segment registers
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Jump to the kernel entry point
call kernel_main
hang:
hlt
jmp hang
gdt:
dw 0, 0, 0, 0 ; null descriptor
dw 0xFFFF, 0, 0x9A00, 0x00CF ; code segment
dw 0xFFFF, 0, 0x9200, 0x00CF ; data segment
gdt_descriptor:
dw gdt - gdt_descriptor - 1
dd gdt
CODE_SEG equ gdt - gdt_descriptor + 8
DATA_SEG equ gdt - gdt_descriptor + 16
kernel_main equ 0x001000
times 510-($-$$) db 0
dw 0xAA55
linker.ld
ENTRY(kernel_main)
SECTIONS
{
. = 0x1000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
kernel.c
void kernel_main() {
char* video_memory = (char*)0xB8000;
char *str = "Hello OS!";
for (int i = 0; *str != '\0'; ++ i) {
video_memory[i] = *str++;
video_memory[++i] = 0x0E;
}
}