Search code examples
assemblyx86bootloaderosdevreal-mode

My operating system doesn't boot in VMWare


I am making an operating system called TriangleOS with a few files like sysldr.sys, kernel.sys, etc. When I run it on VMWare I get this error:

Remove disks or other media. Press any key to restart

I'm compiling on Windows 10. I am using partcopy to create my boot sector. I typed:

partcopy.exe boot.asm 0 200 -f0

This is the content of my file boot.asm:

bits    16
org     0
%include"Floppy16.inc"

start:  jmp main
Print:
lodsb       
or  al, al  
jz  PrintDone
mov ah, 0eh 
int 10h
jmp Print   
PrintDone:
ret
main:  
cli                     
mov     ax, 0x07C0      
mov     ds, ax
mov     es, ax
mov     fs, ax
mov     gs, ax
mov     ax, 0x0000      
mov     ss, ax
mov     sp, 0xFFFF
sti                     
mov     si, msgLoading
call    Print
LOAD_ROOT:
xor     cx, cx
xor     dx, dx
mov     ax, 0x0020                        
mul     WORD [bpbRootEntries]             
div     WORD [bpbBytesPerSector]          
xchg    ax, cx
mov     al, BYTE [bpbNumberOfFATs]        
mul     WORD [bpbSectorsPerFAT]           
add     ax, WORD [bpbReservedSectors]     
mov     WORD [datasector], ax             
add     WORD [datasector], cx
mov     bx, 0x0200                        
call    ReadSectors
mov     cx, WORD [bpbRootEntries]         
mov     di, 0x0200                        
.LOOP:
    push    cx
    mov     cx, 0x000B                    
    mov     si, ImageName                 
    push    di
    rep  cmpsb                            
    pop     di
    je      LOAD_FAT
    pop     cx
    add     di, 0x0020                    
    loop    .LOOP
    jmp     FAILURE
LOAD_FAT:
mov     dx, WORD [di + 0x001A]
mov     WORD [cluster], dx                
xor     ax, ax
mov     al, BYTE [bpbNumberOfFATs]        
mul     WORD [bpbSectorsPerFAT]           
mov     cx, ax
mov     ax, WORD [bpbReservedSectors]     
mov     bx, 0x0200                        
call    ReadSectors
mov     ax, 0x0050
mov     es, ax                            
mov     bx, 0x0000                        
push    bx
LOAD_IMAGE:
mov     ax, WORD [cluster]                
pop     bx                                
call    ClusterLBA                        
xor     cx, cx
mov     cl, BYTE [bpbSectorsPerCluster]   
call    ReadSectors
push    bx
mov     ax, WORD [cluster]                
mov     cx, ax                            
mov     dx, ax                            
shr     dx, 0x0001                        
add     cx, dx                            
mov     bx, 0x0200                        
add     bx, cx                            
mov     dx, WORD [bx]                     
test    ax, 0x0001
jnz     .ODD_CLUSTER 
.EVEN_CLUSTER:
    and     dx, 0000111111111111b         
    jmp     .DONE 
.ODD_CLUSTER:
    shr     dx, 0x0004                    
.DONE:
    mov     WORD [cluster], dx            
    cmp     dx, 0x0FF0                    
    jb      LOAD_IMAGE   
DONE:
     mov     si, msgCRLF
     call    Print
     push    WORD 0x0050
     push    WORD 0x0000
     retf
FAILURE:
mov     si, msgFailure
call    Print
mov     ah, 0x00
int     0x16          
int     0x19          
bootdevice  db 0
ImageName:   db "KRNLDR  SYS"
msgLoading:  db 0x0D, 0x0A, "Reading Kernel Loader", 0x00
msgCRLF:     db 0x0D, 0x0A, 0x00
msgProgress: db ".", 0x00
msgFailure:  db 0x0D, 0x0A, "Can't find Kernel Loader (krnldr.sys). Press Any Key to Reboot", 0x0D, 0x0A, 0x00
TIMES 510-($-$$) DB 0
DW 0xAA55

The file Floppy16.inc is a file driver helper. Here is the code:

%ifndef __FLOPPY16_INC_
%define __FLOPPY16_INC_
bits    16
bpbOEM          db "TriangOS"
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 "TOS FLOPPY "
bsFileSystem:           DB "FAT12   "
datasector  dw 0x0000
cluster     dw 0x0000
absoluteSector db 0x00
absoluteHead   db 0x00
absoluteTrack  db 0x00
ClusterLBA:
    sub     ax, 0x0002
    xor     cx, cx
    mov     cl, BYTE [bpbSectorsPerCluster]
    mul     cx
    add     ax, WORD [datasector]
    ret
LBACHS:
    xor     dx, dx                    
    div     WORD [bpbSectorsPerTrack] 
    inc     dl                        
    mov     BYTE [absoluteSector], dl
    xor     dx, dx                    
    div     WORD [bpbHeadsPerCylinder]
    mov     BYTE [absoluteHead], dl
    mov     BYTE [absoluteTrack], al
    ret
; CX=>Kolko sektori da procita
; AX=>Pocetni sektor
; ES:EBX=>Na koju mem. lokaciju da ga stavi
ReadSectors:
     .MAIN
          mov     di, 0x0005                  
     .SECTORLOOP
          push    ax
          push    bx
          push    cx
          call    LBACHS
          mov     ah, 0x02                    
          mov     al, 0x01                    
          mov     ch, BYTE [absoluteTrack]    
          mov     cl, BYTE [absoluteSector]   
          mov     dh, BYTE [absoluteHead]     
          mov     dl, BYTE [bsDriveNumber]
          int     0x13                        
          jnc     .SUCCESS                    
          xor     ax, ax                      
          int     0x13                        
          dec     di                          
          pop     cx
          pop     bx
          pop     ax
          jnz     .SECTORLOOP                 
          int     0x18
     .SUCCESS
          pop     cx
          pop     bx
          pop     ax
          add     bx, WORD [bpbBytesPerSector]
          inc     ax                          
          loop    .MAIN                       
          ret

%endif

I compiled the boot sector using this command:

nasm.exe -f bin boot.asm -o boot.bin

The project is really big. I made this so that I don't need GRUB. I noticed that my hex editor is at the end 55. Is it normal to be reverse? In my code there is normal 0xAA55. Why does it output Remove disks or other media? How can I fix this problem? Any suggestions?


Solution

  • Primary Problems

    At the top of your code you do this:

    bits    16
    org     0
    %include"Floppy16.inc"
    
    start:  jmp main
    

    The %include"Floppy16.inc" will insert everything in the file floppy16.inc as if it were part of your boot.asm code. The problem is that your Boot Parameter Block (BPB) appears before any code, so the data will literally be executed as code since the bootloader will start executing from physical address 0x07c00. I think you probably should have done this:

    bits    16
    org     0
    start:  jmp main
    nop               ; Place NOP so BPB starts at the 4th byte of binary file. 
                      ; relative(short) JMP is 2 bytes long. NOP acts as 1 byte padding.
    
    %include"Floppy16.inc"
    

    By jumping over the BPB data included by the file floppy16.inc you avoid executing the data as code.


    At boot, this output:

    Remove disks or other media. Press any key to restart

    Suggests there may have been a disk inserted in the system but that there was no bootable media found.

    What I do find curious is that you seem to generate a binary file from your assembler code but then you use this command:

    partcopy.exe boot.asm 0 200 -f0
    

    This will place the assembler source code into the first 512 bytes of the floppy. You want to place the binary file you created onto the floppy. I think you should have used:

    partcopy.exe boot.bin 0 200 -f0
    

    File boot.bin is the binary file that was created from this command:

    nasm.exe -f bin boot.asm -o boot.bin
    

    Since you copied boot.asm into the boot sector of your floppy the last 2 bytes of the sector would NOT contain the word 0xAA55, and thus wouldn't be detected as a bootable floppy. If there was no other bootable media on your virtual machine you would have got the error about removing media and restarting.


    Other Issues

    Fifoernik mentioned in the comments:

    Unrelated but still... Don't initialize your stackpointer at an odd address! Better use the even address mov sp, 0xFFFE

    In the past couple days I wrote a Stackoverflow answer that discussed that issue as well. I'd probably suggest setting SP to 0x0000. A stack that is aligned to an odd word boundary (like 0xffff) will take a significant performance hit if run on real 8086 processors. Setting SP to zero works because it is an even address and the first push of a word onto the stack decrements SP by 2 first and then writes the value. The first word pushed would be at SS:0xfffe .


    As it is your code won't run on anything less than a 386 anyway because you have:

    mov     fs, ax
    mov     gs, ax
    

    fs and gs registers were introduced in the 386 processors. Your code wouldn't run on real 8086/8088/80188/80286 processors. This may be by design, but I felt I should mention it.


    Since you are using instructions like lodsb you should consider setting the direction flag. In your case you seem to be relying on forward movement so I'd recommend the us of the CLD instruction near the beginning of the bootloader. You can't be guaranteed it will be set properly.


    Your code seems to destroy the contents of DL. The BIOS will pass the boot drive to your bootloader through DL. You might consider saving it so that it can be used to read sectors from the drive that was booted. It is possible you are accounting for this, but it isn't readily apparent without seeing the contents of floppy16.inc