我的操作系统无法在 VMWare 中启动
My operating system doesn't boot in VMWare
我正在制作一个名为 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
代码的一部分一样。问题在于您的引导参数块 (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
在过去的几天里,我写了一篇 来讨论这个问题。我可能会建议将 SP 设置为 0x0000。如果在真正的 8086 处理器上 运行,则与奇数字边界(如 0xffff)对齐的堆栈将显着降低性能。将 SP 设置为零是可行的,因为它是一个偶数地址,并且第一个将字压入堆栈会使 SP 先减 2,然后写入价值。推送的第一个词位于 SS:0xfffe .
因为您的代码无论如何都不会 运行 小于 386,因为您有:
mov fs, ax
mov gs, ax
fs
和 gs
寄存器是在 386 处理器中引入的。您的代码不会 运行 在真正的 8086/8088/80188/80286 处理器上。这可能是设计使然,但我觉得我应该提一下。
由于您正在使用 lodsb
之类的指令,因此您应该考虑设置方向标志。在你的情况下,你似乎依赖于向前移动,所以我建议在引导加载程序开头附近使用 CLD
指令。你不能保证它会被正确设置。
您的代码似乎破坏了 DL 的内容。 BIOS 将通过 DL 将引导驱动器传递给您的引导加载程序。您可能会考虑保存它,以便它可用于从启动的驱动器中读取扇区。您可能正在考虑这一点,但如果不查看 floppy16.inc
的内容则不会很明显
我正在制作一个名为 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
代码的一部分一样。问题在于您的引导参数块 (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
在过去的几天里,我写了一篇
因为您的代码无论如何都不会 运行 小于 386,因为您有:
mov fs, ax
mov gs, ax
fs
和 gs
寄存器是在 386 处理器中引入的。您的代码不会 运行 在真正的 8086/8088/80188/80286 处理器上。这可能是设计使然,但我觉得我应该提一下。
由于您正在使用 lodsb
之类的指令,因此您应该考虑设置方向标志。在你的情况下,你似乎依赖于向前移动,所以我建议在引导加载程序开头附近使用 CLD
指令。你不能保证它会被正确设置。
您的代码似乎破坏了 DL 的内容。 BIOS 将通过 DL 将引导驱动器传递给您的引导加载程序。您可能会考虑保存它,以便它可用于从启动的驱动器中读取扇区。您可能正在考虑这一点,但如果不查看 floppy16.inc