Cannot jump or call kernel loaded on 0x8000

I am trying to develop an operating system. The design is this: I have a bootloader loaded on 0x7c00 that loads the second stage and jumps to it from 0x7e00. The second stage is also in real mode and does a lot of things, such as loading gdt, turning on the A20, and switching to protected mode. It also loads a very simple 32-bit kernel at 0x8000. The problem is that I cannot call or jmp to 0x8000, since the kernel does not seem to load (I dumped the memory in VirtualBox). I already performed FAR JMP in the second step to set the CS register. I am testing my OS in VirtualBox.

Code for my bootloader:

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 the 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 the 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, you should print two "X". Commands used to create floppy disks:

  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 

OS running in virtual boxing

+5
source share
1 answer

Reading Problem Stage 3

In the second step, you load the third step by 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 marked the lines with the problems. You efficiently configure AX to prepare for reading, and then overwrite values ​​from 0x800 to configure ES. Move ES settings before setting AH and AL. Change the code to look like this:

  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 probably prevents your second stage from loading the 3rd stage correctly.


Other problems

At the end of the bootloader, you have:

  db 0xAA db 0x55 

This is back to front and should be:

  db 0x55 db 0xAA 

You could write this as:

  dw 0xAA55 

It seems that the problem is that when defining these bytes you do not take into account the byte order.


You correctly jump over the BIOS parameter block in the bootloader, but the BPB should start with the 4th byte in the boot sector. You can force a 2-byte JMP using the short modifier. Then you can put nop after the jump so that the BPB starts at 4th byte.

The 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 petty quibble. Having a stack on the border of WORD (even addresses) works better on 8086 processors. Since you have not been in real mode for a very long time, this does not really matter at all. Usually you use mov sp, 0x0000 in your case, because the first WORD returned will be 0x9000: 0xfffe, since 2 is first subtracted from the SP, and then WORD is pushed onto the stack. In fact, with SP = 0x0000, the stack will begin with a transfer to the top of the segment of 64 KB.


You do not need JMP from label to label if the label is immediately after JMP. Instructions such as:

  jmp Set Set: 

Does nothing, only spends space and loads the processor. I noticed that you did this in many places. This is not part of your problem, just observation. FAR JUMP jmp (code-gdt_start):transfer_control followed by a label will do, as it is used to correctly set the CS descriptor (for protected mode)


When accessing a disk with int 13h you should use the boot disk number provided by the BIOS to your bootloader as the value for DL. Your first and second steps have the following code:

 mov dl , 00h 

This always assumes that you are reading from the first diskette (A :). If you want to use your code on a boot disk other than Floppy A: you need to delete this

+3
source

Source: https://habr.com/ru/post/1240002/


All Articles