x86 - VirtualBox - 找不到可启动媒体

标签 x86 virtual-machine virtualbox bootloader osdev

stackoverflow 上有很多类似标题的问题。我阅读了所有这些,但没有一个能回答我的问题。这就是我打开这个问题的原因。

我正在用汇编器和 C 创建一个操作系统。我发现我必须将 C 代码编译为二进制格式,提取文本部分并将其保存为文件,然后将其转换为 ISO,然后将其安装到磁盘的虚拟光驱中,然后在 VirtualBox 中加载我的操作系统。所以,这是我想避免的很多工作。我不想每次都将我的二进制文件转换为 ISO。

因此,我决定将我的操作系统的二进制机器码放到虚拟硬盘驱动器(VDI 文件)中,然后将其设置为引导顺序的顶部并加载它,而不是从虚拟光驱ISO 加载它。 .

我正在研究如何VDI工作,我发现它通常是动态分配的,并且只存储数据的开头。所以,开始VDI代表一个标题,其余的是存储在虚拟驱动器上的实际数据。所以,我发现数据从某个地址开始(在我的例子中是 0x00200000VDI 文件的开头)。

然后,我基本上是从那个地址填到VDI结尾的带图案的文件 55 AA .所以,我想现在这意味着磁盘是可启动的(因为在第一个扇区的末尾仍然是签名 55 AA )。

我启动了虚拟机,它说:

No bootable medium found! System halted



有没有办法解决这个问题?为什么我的虚拟磁盘仍然无法启动?

编辑

这是实际VDI文件:1.vdi

最佳答案

您没有提供显示引导加载程序以及如何将其放入 VDI 的最小完整可验证示例。但至少您需要将 0xAA55 放在主引导记录的最后 2 个字节中。下面的示例创建了一个简单的引导加载程序;创建一个 2MiB 原始图像;将引导加载程序放置在原始镜像中;并将原始图像转换为 VDI。
boot.asm :

BITS 16
ORG 0x7C00

    xor ax, ax
    mov ds, ax
    mov ss, ax       ; Stack below bootloader
    mov sp, 0x7c00

    mov ax, 0xb800   ; Video segment b800
    mov es, ax

    ; Print Hello with white on light magenta
    mov word [es:0x0], 0x57 << 8 | 'H'
    mov word [es:0x2], 0x57 << 8 | 'e'
    mov word [es:0x4], 0x57 << 8 | 'l'
    mov word [es:0x6], 0x57 << 8 | 'l'
    mov word [es:0x8], 0x57 << 8 | 'o'

    ; End with infinite loop
    cli
endloop:
    hlt
    jmp endloop

; Fill out to 510 bytes and add boot signature
times 510 - ($ - $$) db 0
dw 0xAA55            ; add boot signature at the end of bootloader

然后我使用这个命令来创建引导加载程序文件 boot.bin :
nasm -f bin boot.asm -o boot.bin

创建 2MiB 磁盘镜像文件 1.raw :
dd if=/dev/zero of=1.raw bs=1024 count=2048

放置引导加载程序 boot.bin在文件开头 1.raw不截断文件的其余部分:
dd if=boot.bin of=1.raw conv=notrunc

创建一个名为 1.vdi 的 VDI 镜像来自 1.raw :
rm -f 1.vdi
VBoxManage convertfromraw 1.raw 1.vdi --format VDI

当添加到 VirtualBox 下的虚拟机时,我会在显示屏上看到:

enter image description here

您的 VDI 文件

在您提供的图像文件中 1.vdi我在做 hexdump 时注意到了这一点:

00200000  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
*
00300000


此输出向我表明您反转了文件中引导签名的字节。它应该是 0x55 后跟 0xaa。 0xaa55 作为 WORD 存储,字节颠倒。

有效的引导介质可能不仅仅是让引导签名正确。某些 BIOS 可能会在通常在引导加载程序中找到的前几个字节中搜索某些指令。找不到此类指令(示例通常包括 JMP、XOR、CLI、MOV 之类的内容)可能会导致它认为它不是有效的引导介质。

一种测试末尾的 0xAA55 是否足够的方法我使用了 hexedit 并修改了您的 1.vdi文件看起来像这样:

00200000  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
00200010  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002001f0  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 55 aa <-- Corrected signature
                                                               at 1fe & 1ff
00200200  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
*
00300000


仅凭该更改运行是行不通的。然后我使用了 hexedit 并放置了一个 CLI操作码 (0xFA) 作为扇区的第一个字节。生成的文件现在看起来像:

           v-- CLI instruction
00200000  fa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
00200010  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002001f0  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 55 aa
00200200  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
*
00300000


我已放置 fa作为引导加载程序的第一个字节。现在,当我使用您的图像时,会出现错误 No bootable medium found!系统停止不再出现。这表明 VirtualBox 正在寻找的不仅仅是引导签名,而是在进行某种完整性检查以确定引导加载程序的开始是否是可执行指令。这对于 BIOS 来说并不少见。有些人可能会做这样的检查,有些人可能不会。目前我还没有查看 VirtualBox 源代码来确定它为做出决定而执行的确切检查。

关于x86 - VirtualBox - 找不到可启动媒体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43566542/

相关文章:

azure - 在 Azure VM 上运行的 Docker 容器中使用 Azure 托管标识

sql-server - Azure VM 上 SQL Server 的连接字符串

windows-8 - 如何让 Windows 8 Phone 模拟器通过 VirtualBox 运行?

ubuntu - 安装在 USB 驱动器上的 ubuntu 上的 CUDA/OpenCL

docker - 如何使用 docker-machine 更改虚拟机配置

C++ SEH - EXCEPTION_DISPOSITION 枚举和 __except() 过滤器表达式之间的相关性

c - 在DOS下处理以太网中断

linux - 如何在 VM 中查找主机的凭据?

linux - C 中意外的段错误

linux - Cygwin:兼容性问题