I am trying to develop an operating system. The design is this: I have a bootloader loaded at 0x7c00 which loads the second stage and jumps to it at 0x7e00. The second stage is also in real mode and does a lot of stuff such as loading gdt, enabling A20 and switching to protected mode. It also loads a very simple 32 bit kernel at 0x8000. The problem now is that I am not able to call or jmp to 0x8000 as the kernel doesn't seem to get loaded(I did a memory dump in VirtualBox). I have already done a FAR JMP within the second stage to set the CS register. I am testing my OS in VirtualBox.
Code for my boot loader:
org 0x7c00
bits 16
Start:
jmp Reset
bpbOEM DB "SKULLOS "
bpbBytesPerSector: DW 512
bpbSectorsPerCluster: DB 1
bpbReservedSectors: DW 1
bpbNumberOfFATs: DB 2
bpbRootEntries: DW 224
bpbTotalSectors: DW 2880
bpbMedia: DB 0xF0
bpbSectorsPerFAT: DW 9
bpbSectorsPerTrack: DW 18
bpbHeadsPerCylinder: DW 2
bpbHiddenSectors: DD 0
bpbTotalSectorsBig: DD 0
bsDriveNumber: DB 0
bsUnused: DB 0
bsExtBootSignature: DB 0x29
bsSerialNumber: DD 0xa0a1a2a3
bsVolumeLabel: DB "MOS FLOPPY "
bsFileSystem: DB "SKFS "
Set:
mov al , 02h
mov ah , 00h
int 10h
jmp Print
Print:
mov al , 'A'
mov bl , 0Fh
mov cx , 01h
mov ah , 09h
int 10h
jmp Reset
Reset:
; mov dl , 0x00
mov [0x500] , dl
mov ah , 0x00
int 0x13
jc Reset
mov ax , 0x7E0
mov es , ax
xor bx , bx
mov ah , 0x02
mov al , 1
mov ch , 0
mov cl , 2
mov dh , 0
mov dl , [0x500]
int 0x13
jmp 0x0000 :0x7e00
times 510-($-$$) db 0
db 0x55
db 0xAA
Code for second stage:
org 0x7E00
bits 16
Start:
jmp Setup
;;;;;;;;;;;;;stack;;;;;;;;;;
Setup:
cli
xor ax , ax
mov ds , ax
mov es , ax
mov ax , 0x9000
mov ss , ax
mov sp , 0xFFFF
sti
jmp Set
;;;;;;;;;;;;;video;;;;;;;;;;;
Set:
mov al , 03h
mov ah , 00h
int 10h
mov ah , 09h
mov al , 'A'
mov bh , 00h
mov bl , 0x0F
mov cx , 01h
int 10h
jmp loadgdt
;;;;;;;;;;;;gdt;;;;;;;;;;;;;;;
gdt_start:
null:
dd 0
dd 0
code:
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
data:
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
end:
load: dw end - gdt_start -1
dd null
;;;;;;;;;;;;;loadgdt;;;;;;;;;;
loadgdt:
lgdt [load]
jmp A20
;;;;;;;;;;;;A20;;;;;;;;;;;;;;;
A20:
mov ax , 0x2401
int 0x15
jc A20
jmp Reset
;;;;;;;;;;;;;floppy;;;;;;;;;;;
Reset:
mov ah , 00h
mov dl , [0x500]
int 13h
jc Reset
jmp Read
Read:
mov ah , 02h
mov al , 01h
mov ch , 00h
mov cl , 03h
mov dh , 00h
mov dl , [0x500]
mov ax , 0x800
mov es , ax
xor bx , bx
int 13h
jc Read
jmp Begin
Begin:
mov ah , 09h
mov al , 'G'
mov bh , 00h
mov bl , 0x0F
mov cx , 01h
int 10h
jmp protected
;;;;;;;;;;;switching to protected;;;;
protected:
mov ah , 09h
mov al , 'P'
mov bh , 00h
mov bl , 0x0F
mov cx , 01h
int 10h
xor ax, ax
mov ds, ax
cli
mov eax, cr0
or eax , 1
mov cr0 , eax
jmp (code-gdt_start):transfer_control
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bits 32
transfer_control:
mov ax, (data-gdt_start)
mov ds, ax
mov ss, ax
mov es, ax
mov esp, 90000h
mov [0xB8000], word 0x0F58 ; Print 'X'
call 0x8000
hlt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
times 512-($-$$) db 0
Code for kernel:
org 0x8000
bits 32
jmp Start
Start:
mov ax , 0x10
mov ds , ax
mov ss, ax
mov es, ax
mov esp, 90000h
mov [0xB8002], word 0x0F58 ; Print 'X'
ret
times 512-($-$$) db 0
Currently, only one 'X' is being printed. However, two 'X' should be printed. Commands used to create floppy:
dd seek=0 if=boot of=os.img
dd seek=1 if=second_stage of=os.img
dd seek=2 if=third_stage of=os.img
In the second stage you load the third stage doing this:
Read:
mov ah , 02h ; Setup AH
mov al , 01h ; Setup AL
mov ch , 00h
mov cl , 03h
mov dh , 00h
mov dl , [0x500]
mov ax , 0x800 ; Destroy contents of AX
mov es , ax ; Setup ES=0x800
xor bx , bx
int 13h
I have marked the lines with the problems. You effectively set up AX to get ready for the read and then overwrite the values with 0x800 to set up ES. Move setting up ES before you setup AH and AL. Modify the code to look like:
Read:
mov ax , 0x800
mov es , ax ; Setup ES=0x800
mov ah , 02h ; Setup AH
mov al , 01h ; Setup AL
mov ch , 00h
mov cl , 03h
mov dh , 00h
mov dl , [0x500]
xor bx , bx
int 13h
This likely prevents your second stage from loading the 3rd stage properly.
At the end of the bootloader you have:
db 0xAA
db 0x55
This is backwards and should be:
db 0x55
db 0xAA
You could have written it as:
dw 0xAA55
The issue appears to be that you didn't take little endianness into account when defining these bytes.
You properly jump over the BIOS Parameter Block in the bootloader, but the BPB needs to start at the 4th byte in the boot sector. You can force a 2-byte JMP using the short
modifier. You can then place a nop
after the jump so that the BPB starts at the 4th byte.
Change:
jmp Reset
bpbOEM DB "SKULLOS "
To:
jmp short Reset
nop ; 1 byte padding as BPB needs to start at 4th byte (short jmp takes 2 bytes)
bpbOEM DB "SKULLOS "
mov sp , 0xFFFF
should probably be mov sp, 0x0000
. This is just a minor nitpick. Having the stack on a WORD boundary (even addresses) performs better on 8086 processors. Since you are not in real mode very long it doesn't much matter at all. Usually you'd use mov sp, 0x0000
in your case because the first WORD pushed will be at 0x9000:0xfffe since 2 is subtracted from SP first and then the WORD pushed onto the stack. Effectively with SP=0x0000 the stack will start by wrapping to the top of the 64k segment.
You don't need to JMP from label to label if the label is right after the JMP. Instructions like:
jmp Set
Set:
does nothing but waste space and take CPU cycles. I noticed you did that in quite a few places. This isn't part of your problem, just an observation. The FAR JUMP jmp (code-gdt_start):transfer_control
followed by the label is fine since that is used to to set the CS descriptor properly (for protected mode)
When doing disk access with int 13h
you should be using the boot drive number passed by the BIOS to your bootloader as the value for DL. Your first and second stages have code like:
mov dl , 00h
This always assumes you are reading from the first floppy (A:). If you want to use your code on a boot drive other than Floppy A: you'll want to remove this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With