assembly - 我的操作系统无法在 VMWare 中启动

标签 assembly x86 bootloader osdev real-mode

我正在制作一个名为 TriangleOS 的操作系统,其中包含一些文件,例如 sysldr.sys、kernel.sys 等。当我在 VMWare 上运行它时,出现此错误:

Remove disks or other media. Press any key to restart

我正在 Windows 10 上进行编译。我正在使用 partcopy 创建引导扇区。我输入:

partcopy.exe boot.asm 0 200 -f0

这是我的文件 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

文件Floppy16.inc是一个文件驱动程序助手。这是代码:

%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

我使用以下命令编译了引导扇区:

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

这个工程确实很大。我这样做是为了不需要 GRUB。我注意到我的十六进制编辑器位于末尾 55。反转正常吗?在我的代码中有正常的0xAA55。为什么它输出Remove disks or other media? 我该如何解决这个问题?有什么建议吗?

最佳答案

主要问题

在代码顶部执行以下操作:

bits    16
org     0
%include"Floppy16.inc"

start:  jmp main

%include"Floppy16.inc" 会将所有内容插入到文件 floppy16.inc 中,就好像它是 boot.asm 的一部分一样> 代码。问题是引导参数 block (BPB) 出现在任何代码之前,因此数据实际上将作为代码执行,因为引导加载程序将从物理地址 0x07c00 开始执行。我认为你可能应该这样做:

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"

通过跳过文件 floppy16.inc 包含的 BPB 数据,您可以避免将数据作为代码执行。


启动时,输出:

Remove disks or other media. Press any key to restart

表明系统中可能已插入磁盘,但未找到可启动媒体。

我确实感到好奇的是,您似乎从汇编代码生成了一个二进制文件,但随后您使用了以下命令:

partcopy.exe boot.asm 0 200 -f0

这会将汇编器代码放入软盘的前 512 字节中。您想要将创建的二进制文件放入软盘上。我认为你应该使用:

partcopy.exe boot.bin 0 200 -f0

文件boot.bin是从此命令创建的二进制文件:

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

由于您将 boot.asm 复制到软盘的引导扇区中,该扇区的最后 2 个字节将不包含字 0xAA55,因此不会被检测为可引导软盘。如果您的虚拟机上没有其他可启动媒体,您将收到有关删除媒体并重新启动的错误。


其他问题

Fifoernik 在评论中提到:

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

这几天我写了一个Stackoverflow answer也讨论了这个问题。我可能建议将 SP 设置为 0x0000。如果在真正的 8086 处理器上运行,与奇数字边界(如 0xffff)对齐的堆栈将遭受显着的性能影响。将 SP 设置为零是可行的,因为它是偶数地址,并且第一次将字压入堆栈时会先将 SP 减 2,然后写入该值。推送的第一个字将位于 SS:0xfffe 。


事实上,您的代码无论如何都不会在低于 386 的任何设备上运行,因为您有:

mov     fs, ax
mov     gs, ax

fsgs 寄存器是在 386 处理器中引入的。您的代码无法在真正的 8086/8088/80188/80286 处理器上运行。这可能是有意为之,但我觉得我应该提一下。


由于您正在使用像 lodsb 这样的指令,您应该考虑设置方向标志。在您的情况下,您似乎依赖于向前移动,因此我建议在引导加载程序开头附近使用 CLD 指令。您不能保证它会被正确设置。


您的代码似乎破坏了DL的内容。 BIOS 将通过DL 将引导驱动器传递给引导加载程序。您可以考虑保存它,以便可以使用它从启动的驱动器中读取扇区。您可能正在考虑这一点,但如果没有看到 floppy16.inc

的内容,这一点并不明显

关于assembly - 我的操作系统无法在 VMWare 中启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34679437/

相关文章:

c - 来自 x86_64 Linux 中内联 asm 的系统调用?

vba - 如何检测计算机是 32 位还是 64 位?

assembly - ESP 和 EAX 一样通用吗?

memory-management - 烧录到闪存的​​特定扇区

c - 以下程序集对以下 .c 文件做了什么

assembly - MSP430 SWAP 字节解释汇编

operating-system - 制作定制版 mikeOS 的可启动闪存驱动器

linux-kernel - 如何将Linux内核Bin转为ELF格式

c - X86 32b 汇编 - 使用 atoll

c - 不知道为什么我会收到链接错误