In my previous question, I had an issue using ah=0x2 in which I could not read more than 65 sectors. I was recommended to use ah=42h, and after changing my code, I can confirm that it does read more than 65 sectors at a time, without any issue in reading and loading so far. However, qemu still will enter a reboot loop. Here is my code so far.
loader.asm
[bits 16]
[extern kernel]
section .boot
global boot
KERNEL_SIZE_SECTORS equ 255 ;Kernel size in sectors
jmp boot
dap:
db 0x10
db 0
dw KERNEL_SIZE_SECTORS
dw 0 ;
dw 0x07e0 ;value recommended by a friend
dq 0 ;Start reading from the second sector
print:
pusha
start:
mov al, [bx]
cmp al, 0
je done
mov ah, 0x0e
int 0x10
add bx, 1
jmp start
done:
popa
ret
print_nl:
pusha
mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
popa
ret
print_hex:
pusha
mov cx, 0
hex_loop:
cmp cx, 4
je end
mov ax, dx
and ax, 0x000f
add al, 0x30
cmp al, 0x39
jle step2
add al, 7
step2:
mov bx, HEX_OUT + 5
sub bx, cx
mov [bx], al
ror dx, 4
add cx, 1
jmp hex_loop
end:
mov bx, HEX_OUT
call print
popa
ret
HEX_OUT:
db '0x0000',0
disk_read_error: db "Disk read error!", 0
disk_err: ;Label for any disk errors
mov bx, disk_read_error ;Print the disk error
call print
call print_nl
mov dh, ah ;Load error code in ah register
call print_hex
jmp $
boot:
mov ax, 0x2401 ;GDT preperation
int 0x15
mov ax, 0x3 ;Set the VGA mode, unknown at boot
int 0x10
mov [disk], dl ;Load the disk
mov ah, 42h ;Do modern disk reading (no fuckery)
mov dl, [disk] ;Account for cosmic bit flips
mov si, dap ;Load disk address packet
int 0x13
jc disk_err ;Jump if disk read error
cli ;Clear the interrupts
lgdt [GDT_POINTER] ;Load the GDT using a gdt pointer
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:boot2
boot2:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
GDT_START:
dq 0x0
GDT_CODE:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
GDT_DATA:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
GDT_END:
GDT_POINTER:
dw GDT_END - GDT_START
dd GDT_START
disk:
db 0x0
CODE_SEG equ GDT_CODE - GDT_START
DATA_SEG equ GDT_DATA - GDT_START
times 510 - ($-$$) db 0
dw 0xaa55
copy_target:
[bits 32]
loaded_msg: db "Operating system loaded",0
;Message here to verify disk read
mov esi, loaded_msg
mov ebx, 0xb8000
.loop: ;Print a message using a loop
lodsb
or al, al
jz load_kernel ;If the message is finished, load kern
or eax,0x0F00
mov word [ebx], ax
add ebx,2
jmp .loop
load_kernel:
mov esp, kernel_stack_top;Load the stack to call C functions
call kernel ;Call the actual kernel
halt:
cli
hlt
section .bss
align 4
kernel_stack_bottom: equ $ ;equ the current address for the stack
resb 16384 ;Use 16kb for stack size
kernel_stack_top: ;Top of the stack
Linker script
ENTRY(boot)
OUTPUT_FORMAT("binary")
SECTIONS {
. = 0x7c00;
.text :
{
*(.boot)
*(.text)
}
.rodata :
{
*(.rodata)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
Kernel.c file
void kernel() {
const short color = 0x0F00;
const char* hello = "Hello world!";
short* vga = (short*)0xb8000;
for (int i = 0; i<16;++i)
vga[i+80] = color | hello[i];
}
Makefile
CC = i686-elf-gcc
LD = i686-elf-gcc
VM = qemu-system-x86_64
ASM = nasm
BOOTLOADER_FLAGS = -felf32
BOOTLOADER_INFILE = ./loader/loader.asm
BOOTLOADER_OUTFILE = ./bin/loader.o
KERNEL_FLAGS = -nostdlib -ffreestanding -nostdlib -Wall -Wextra -Werror -std=c99 $(KERNEL_STDLIB)
KERNEL_INFILE = ./kernel/kernel.c
KERNEL_OUTFILE = ./bin/kernel.o
KERNEL_STDLIB = -Istdlib/
KERNEL_SRCS = $(shell find . -name '.ccls-cache' -type d -prune -o -type f -name '*.c' -print | sed -e 's/ /\\ /g')
LINKER_FILE = ./build/linker.ld
LINKER_FLAGS = -ffreestanding -O2 -nostdlib $(BOOTLOADER_OUTFILE) $(KERNEL_OUTFILE) -lgcc
OS_NAME = esf-pmc1
all:
@$(ASM) $(BOOTLOADER_FLAGS) $(BOOTLOADER_INFILE) -o $(BOOTLOADER_OUTFILE)
@$(CC) $(KERNEL_INFILE) $(BOOTLOADER_OUTFILE) -o $(OS_NAME).bin $(KERNEL_FLAGS) -T ./build/linker.ld
dd if=/dev/zero of=$(OS_NAME).img bs=512 count=2880
dd if=$(OS_NAME).bin of=$(OS_NAME).img conv=notrunc
run:
@qemu-system-x86_64 -fda $(OS_NAME).img
clean:
@rm -r iso/boot/*.bin
@rm -r *.iso
When placing jmp $
's, I can trace that int 0x13 has no problems, however, when it executes jmp CODE_SEG:boot2
, then it will enter a reboot loop. If I place a jmp $
before the long jump, qemu will not enter the loop.
Edit: After removing the disk reading code, and the moving boot2 inside the first sector, my code no longer enters a reboot loop. I am currently thinking that I may have not used ah=42h correctly