I am working on a small kernel that transitions from real mode to protected mode. The initial setup is in boot.asm, which then jumps to kernel.asm.
In kernel.asm, I am able to print the character 'H' directly to the video buffer. However, when I attempt to print a string, it does not work as expected. I suspect this issue may be related to segmentation.
Here are the steps I’ve already taken:
Moved the string to the data section—this did not resolve the issue.
Set the Data Segment register (DS) to 0x1000 and 0—neither approach worked.
Other examples I found online show similar methods for printing a single character, which work correctly in my case. I have attached the following files for your review:
Code: Select all
boot.asm
Makefile (note: it is somewhat messy)
; boot.asm
org 0x7C00 ; Origin, as bootloaders start at this address
[BITS 16] ; 16-bit real mode
start:
mov [BOOT_DISK], dl ; Store the boot disk number (from DL register) into BOOT_DISK.
; Display a message to indicate this is the first file
mov ah, 0x0E
mov al, 'H'
int 0x10
mov al, 'i'
int 0x10
mov al, '!'
int 0x10
call timer
mov ebx, 0x1000
; Set up registers for reading from disk
mov dh, 2 ; Set DH register to read 2 sectors.
mov ah, 0x02 ; BIOS interrupt function 0x02 - Read sectors.
mov al, dh ; Number of sectors to read (stored in DH).
mov ch, 0x00 ; Cylinder number (0).
mov dh, 0x00 ; Head number (0).
mov cl, 0x02 ; Starting sector (2).
mov dl, [BOOT_DISK] ; Disk number (boot disk).
int 0x13
; Check for error
jc disk_read_error ; If carry flag is set, there was an error
call print_mem
call timer
;; stop interruptions
cli
;; Set the video mode to text mode (80x25 16-color)
mov ah, 0x0
mov al, 0x3
int 0x10
;; Load the descriptor table
lgdt [gdt_descriptor]
;; turn on protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_SEG:flush_pipeline
disk_read_error:
; Display an error message
mov ah, 0x0E
mov al, 'E'
int 0x10
mov al, 'r'
int 0x10
mov al, 'r'
int 0x10
mov al, 'o'
int 0x10
mov al, 'r'
int 0x10
hlt ; Halt the CPU
print_mem:
mov si, 0
loop:
mov al, 0x1000[si] ; move counter to the begin of the buffer
; bios printing service
mov ah, 0x0e
mov bh, 0x00
mov bl, 0x07
int 10h
;next element
inc si
cmp si,100
jl loop
ret
timer:
; wait this time that actually
; is not very precise
mov cx, 0x000F
mov dx, 0x4240
mov al,0
mov ah, 0x86
int 0x15
ret
gdt_start:
gdt_null:
dd 0
dd 0
gdt_code:
dw 0xFFFF
dw 0x0000
db 0x00
db 10011010b
db 11001111b
db 0x00
gdt_data:
dw 0xFFFF
dw 0x0000
db 0x00
db 10010010b
db 11001111b
db 0x00
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
[bits 32]
flush_pipeline:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esi, hello_str ; Load the address of the string
mov edi, 0xB8000 ; Video memory starts at address 0xB8000
call print_string
jmp 0x1000
print_string:
lodsb ; Load byte at address DS:SI into AL
test al, al
jz .done ; If null terminator, finish
mov ah, 0x0F ; Attribute byte: white on black
stosw ; Store word at ES:DI (AL=character, AH=attribute)
jmp print_string
.done:
ret
;; constants
hello_str db 'protected mode ok', 0
BOOT_DISK: db 0
;;variables
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
times 510-($-$$) db 0 ; Pad the rest of the 512-byte sector with zeros
dw 0xAA55 ; Boot sector signature
Code: Select all
;; kernel.asm
[bits 32]
;; not working also !
;;section .data
;; hello_kernel db 'kernel ok', 0
section .text
;; it works !
mov ah, 0x0F
mov al, hello_kernel ; Load the address of the string
mov [0xB8000 + 160], eax ; Video memory starts at address 0xB8000
;;it doesnt works !
mov esi, hello_kernel ; Load the address of the string
mov edi, 0xB8000 ; Video memory starts at address 0xB8000
call print_string
jmp $
print_string:
lodsb ; Load byte at address DS:SI into AL
test al, al
jz .done ; If null terminator, finish
mov ah, 0x0F ; Attribute byte: white on black
stosw ; Store word at ES:DI (AL=character, AH=attribute)
jmp print_string
.done:
ret
hello_kernel db 'kernel ok', 0
times 510-($-$$) db 0 ; Pad the rest of the 512-byte sector with zeros
Code: Select all
# Define the targets and their source files
BOOTLOADER = boot
BOOTLOADER_SRC = boot.asm
KERNEL_IMG = kernel
KERNEL_SRC = kernel.asm
ASM = nasm
ASM_FLAGS = -f bin -g
# Default target to build both bootloader and kernel image
all: $(BOOTLOADER) $(KERNEL_IMG)
# Rule to build the bootloader
$(BOOTLOADER): $(BOOTLOADER_SRC)
$(ASM) $(ASM_FLAGS) $(BOOTLOADER_SRC) -o $(BOOTLOADER).bin
# Rule to build the kernel image
$(KERNEL_IMG): $(KERNEL_SRC)
$(ASM) $(ASM_FLAGS) $(KERNEL_SRC) -o $(KERNEL_IMG).bin
# Clean rule to remove both binaries
clean:
rm -f $(BOOTLOADER).bin $(KERNEL_IMG).bin os.img disk.img
image:
# Create an empty 1.44MB disk image
dd if=/dev/zero of=disk.img bs=512 count=2880
# Write the boot binary to the first sector
dd if=$(BOOTLOADER).bin of=disk.img bs=512 count=1 conv=notrunc
# Write the kernel binary to the appropriate sector (sector 2)
dd if=$(KERNEL_IMG).bin of=disk.img bs=512 count=1 seek=1 conv=notrunc
image_old:
dd if=$(BOOTLOADER).bin of=$(BOOTLOADER).img bs=512 count=1
dd if=$(KERNEL_IMG).bin of=$(KERNEL_IMG).img bs=512 count=1
cat $(BOOTLOADER).img $(KERNEL_IMG).img > os.img
run:
make all
make image
qemu-system-x86_64 -fda disk.img -s -S
run_old:
make all
make image_old
qemu-system-x86_64 -fda os.img
.PHONY: all clean
I am using make run to build and execute the kernel. Despite reviewing various threads and resources, I haven’t been able to find a solution related to the jump from real mode to protected mode.
Thank you very much for your assistance.
Best regards,
[Your Name]
I alread try to read some threads here and also I got this code as example ;
https://github.com/mell-o-tron/OS-Reference/tree/main/7
but the buy is doing in the kernel.cpp exactly as I am doing in the block which works.