According to this tutorial, it’s enough to create a simple operating system with switching to protected mode as easy as the following code without the need for other well-known actions, such as turning on the A20 ...
In any case, I am new to this domain, I wrote the following code, as they exactly mentioned, with a modification inspired by this https://stackoverflow.com/a/360960/
Code structure: This simple operating system should boot briefly as follows:
- Download / read 15 sectors
- Enable GDT
- Switch to protected mode (And print "Successfully landed in 32-bit protected mode").
- Download the kernel and print "X"
However, the emulator is still rebooting. Please attach all code.
bootloader.asm
[bits 16] [org 0x7C00] KERNEL_OFFSET equ 0x1000 xor ax, ax mov ds, ax mov es, ax mov [BOOT_DRIVE], dl mov ax, 0x07E0 ; End of stack cli mov ss, ax mov sp, 0x1200 ; Size of Stack. By this, we assume that stack starts at 9000h ; of size 1200h and ends at 7E00h to avoid being overwritten. sti call load_kernel call switch_to_pm jmp $ %include "src/functions/disk_load.asm" load_kernel: mov bx, KERNEL_OFFSET mov dh, 15 mov dl, [BOOT_DRIVE] call disk_load ret ; Global variables BOOT_DRIVE db 0 SECTORS db 0 MSG_PROT_MODE db "Successfully landed in 32-bit Protected Mode" , 0 %include "src/functions/gdt.asm" %include "src/functions/switch_to_pm.asm" [ bits 32] ; This is where we arrive after switching to and initialising protected mode. BEGIN_PM: mov ebx , MSG_PROT_MODE call print_string_pm ; Use our 32 - bit print routine. ;call KERNEL_OFFSET ; Now jump to the address of our loaded ; kernel code , assume the brace position , ; and cross your fingers. Here we go ! jmp $ ; Hang. %include "src/functions/writing_video_mode.asm" ; Bootsector padding times 510-($-$$) db 0 dw 0xAA55 ; 15 sector padding times 15*256 dw 0xDADA
disk_load.asm
disk_load: mov [SECTORS], dh mov ch, 0x00 ;C=0 mov dh, 0x00 ;H=0 mov cl, 0x02 ;S=2 next_group: mov di, 5 ;Max 5 tries again: mov ah, 0x02 ;Read sectors mov al, [SECTORS] int 0x13 jc maybe_retry sub [SECTORS], al ;Remaining sectors jz ready mov cl, 0x01 ;Always sector 1 xor dh, 1 ;Next head on diskette! jnz next_group inc ch ;Next cylinder jmp next_group maybe_retry: mov ah, 0x00 ;Reset diskdrive int 0x13 dec di jnz again jmp disk_error ready: ret disk_error: mov ah, 0x0e mov al, 'Y' int 0x10 jmp $ DISK_ERROR_MSG db "Disk read error!", 0
gdt.asm
gdt_start: gdt_null: dd 0x0 ; ' dd ' means define double word ( ie 4 bytes ) dd 0x0 gdt_code: dw 0xffff dw 0x0 db 0x0 db 10011010b ; 1 st flags , type flags db 11001111b ; 2 nd flags , Limit ( bits 16 -19) db 0x0 gdt_data: dw 0xffff dw 0x0 db 0x0 db 10010010b ; 1 st flags , type flags db 11001111b ; 2 nd flags , Limit ( bits 16 -19) db 0x0 gdt_end: gdt_descriptor: dw gdt_end - gdt_start - 1 dd gdt_start CODE_SEG equ gdt_code - gdt_start DATA_SEG equ gdt_data - gdt_start
switch_to_pm.asm
[ bits 16 ] switch_to_pm: cli lgdt [ gdt_descriptor ] mov eax , cr0 or eax , 0x1 mov cr0 , eax jmp CODE_SEG:init_pm [ bits 32 ] init_pm: mov ax, DATA_SEG mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax mov ebp , 0x90000 mov esp , ebp call BEGIN_PM
And to make sure that we land in protected mode:
writing_video_mode.asm
[ bits 32] VIDEO_MEMORY equ 0xb8000 WHITE_ON_BLACK equ 0x0f print_string_pm: push eax push ebx push edx mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem. print_string_pm_loop: mov al, [ebx] mov ah, WHITE_ON_BLACK cmp al, 0 je print_string_pm_done mov [edx], ax add ebx, 1 add edx, 2 jmp print_string_pm_loop print_string_pm_done: pop edx pop ebx pop eax ret
kernel.c
void main () { char * video_memory = (char *) 0xb8000; *video_memory = 'X'; }
By the way, I use this Makefile :
all: bootloader.bin kernel.bin bootloader.bin: src/bootloader.asm nasm src/bootloader.asm -f bin -o output/bootloader.bin kernel.o: src/kernel/kernel.c gcc -ffreestanding -c src/kernel/kernel.c -o output/kernel.o -m32 kernel.bin: kernel.o ld -o output/kernel.bin -Ttext 0x1000 --oformat binary output/kernel.o -melf_i386 clean: rm -f output
and to move it to flash, I use the following commands:
cat output/bootloader.bin output/kernel.bin > os-image sudo dd if=os-image of=/dev/sdb bs=512 conv=notrunc && sync
To run it, I use qemu with this command:
qemu-system-i386 -hda /dev/sdb
Noting that / dev / sdb is my flash drive.
Problem: In fact, the code lands in protected mode (Ie Print “Successfully landed in 32-bit protected mode”) only when disconnecting / commenting call KERNEL_OFFSET in bootloader.asm . However, when you enable this line, it starts loading and rebooting.
I hope I have provided all the necessary information. It seems to me that the future path should not be so. Any comments are welcome.