使用自定义引导加载程序创建可引导 ISO 映像

Creating a bootable ISO image with custom bootloader

我正在尝试将我用汇编语言编写的引导加载程序转换为 ISO 映像文件。以下是来自 MikeOS 引导加载程序的代码。这是我的引导程序代码:

   BITS 16
start:
    mov ax, 07C0h     ; Set up 4K stack space after this bootloader
    add ax, 288       ; (4096 + 512) / 16 bytes per paragraph
    mov ss, ax
    mov sp, 4096

    mov ax, 07C0h     ; Set data segment to where we're loaded
    mov ds, ax

    mov si, text_string   ; Put string position into SI
    call print_string ; Call our string-printing routine

    jmp $         ; Jump here - infinite loop!
    text_string db 'This is my cool new OS!', 0

    print_string:         ; Routine: output string in SI to screen
    mov ah, 0Eh       ; int 10h 'print char' function

.repeat:
    lodsb         ; Get character from string
    cmp al, 0
    je .done      ; If char is zero, end of string
    int 10h           ; Otherwise, print it
    jmp .repeat
.done:
    ret

    times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
    dw 0xAA55     ; The standard PC boot signature

我输入了以下命令:

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

此命令运行良好,并提供 .bin 输出。接下来我输入了以下命令:

dd if=boot.bin of=floppy.img count=1 bs=512 

这也很好用,并为我提供了 .img 输出文件。当我键入此命令时:

dd if=boot.bin of=floppy.img skip seek=1 count=1339

我收到以下错误:dd: unrecognized operand ‘skip’。我在 DD 文档中读到,skip 属性必须分配一个数字。任何想法我应该使用 skip 属性键入什么数字(例如 skip=1)。

接下来我输入以下命令:

mkdosfs -C floppy.img 1440 

我收到以下错误:mkdosfs: unable to create floppy.img。如何解决我遇到的问题?还有另一种更简单的方法可以将我的引导加载程序 .bin 文件转换为 ISO 映像吗?

您似乎找到了从这个 Whosebug Answer 创建可引导 ISO 映像的示例。不幸的是,您选择了一个在很多方面都不正确的公认答案。假装你从来没有看到那个答案。

在大多数 Linux 发行版中,存在名为 genisoimagemkisofs 的程序。现在它们实际上是同一个程序。无论您有什么,都可以在下面的示例中替换。我的示例将假定 ISO 创建实用程序称为 genisoimage.


在您的问题中,您在名为 boot.asm 的文件中有一些引导加载程序代码。您正确地 assemble 将此设置为引导扇区二进制映像:

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

这将创建 boot.bin,这是您的引导扇区。下一步是创建软盘映像并将 boot.bin 放在第一个扇区。你可以这样做:

dd if=/dev/zero of=floppy.img bs=1024 count=1440
dd if=boot.bin of=floppy.img seek=0 count=1 conv=notrunc

第一个命令简单地使零填充的磁盘映像等于 1.44MB 软盘的大小(1024*1440 字节)。第二个命令将 boot.bin 放入 floppy.img 的第一个扇区而不截断文件的其余部分。 seek=0 表示查找第一个扇区(512 字节是 DD 的块的默认大小)。 count=1 指定我们只想从 boot.bin 复制 1 个扇区(512 字节)。 conv=notrunc 表示在写入输出文件后,剩余的磁盘映像将保持完整(未被截断)。


如上所示构建磁盘映像后,您可以使用以下命令创建 ISO 映像:

mkdir iso
cp floppy.img iso/
genisoimage -quiet -V 'MYOS' -input-charset iso8859-1 -o myos.iso -b floppy.img \
    -hide floppy.img iso/

上面的命令首先创建一个名为 iso 的子目录,其中将包含要放置到最终 CD-ROM 映像中的文件。第二个命令只是将我们的 floppy.img 复制到 iso 目录,因为我们需要它来启动。第三个命令执行繁重的工作并构建 ISO 映像。

  • -V 'MYOS' 设置卷标(可以随意)
  • -input-charset iso8859-1 设置正在使用的字符集。不要改变它
  • -o myos.iso 表示 ISO 图像将输出到文件 myos.iso
  • -b floppy.img 表示我们的 ISO 将是可引导的,并且正在使用的引导映像是文件 floppy.img
  • -hide floppy.img 不是必需的,但它隐藏了最终 ISO 目录列表中的引导映像。如果您挂载此 ISO 并在其上执行 ls 以列出文件,floppy.img 将不会出现。
  • 命令末尾的
  • iso/ 是用于构建 ISO 映像的目录。它至少需要包含我们的可引导软盘映像,但您可以将任何其他文件放入 iso/ 目录。

生成的ISO镜像myos.iso可以启动。使用 QEMU 启动这样一个镜像的例子:

qemu-system-i386 -cdrom ./myos.iso

对于光盘;有一个规范 ("El Torito") 描述了 bootable CD 的工作原理;在前 16 个(2048 字节)扇区未使用的地方,固件使用 "boot catalogue" 来决定它应该使用哪个引导加载程序(因此您可以使用一张 CD 来引导非常不同的系统 - 例如 PC BIOS、UEFI、PowerPC 等),然后是引导加载程序本身。

仅 "PC BIOS" 就有 3 种可能性:

  • 模拟软盘(使用存储在 CD 上的 "floppy disk image")
  • 模拟硬盘(使用 "hard disk image" 存储在 CD 上)
  • 没有仿真

前两个选项主要是为了兼容(不支持从 CD 启动的老 OSs,如 MS-DOS);并具有性能影响(例如,要模拟加载一个 512 字节的虚拟扇区,固件必须加载一个真正的 2048 字节的扇区并丢弃多余的 1536 字节)。在过去 15 年以上的任何 OS designed/written 都应该使用 "no emulation".

对于"no emulation":

  • 固件会加载整个引导加载程序(最多可达 512 KiB),而不仅仅是一个扇区
  • CD 上的扇区是 2048 字节(而不是 512 字节);并且应该通过加载。 "int 0x13 extensions"(而不是您用于软盘的 old/limited "CHS disk functions")
  • 不需要 BIOS 参数块(对于软盘应该被认为是必需的)
  • 不需要分区table(对于硬盘应该算是强制分区,包括GPT)
  • 您可能希望支持 ISO9660 作为文件系统(以查找内核 and/or 引导加载程序需要加载的其他文件)而不是 FAT。

还要注意(通常)对于 "PC BIOS",您可能需要 5 个不同的引导装载程序(一个用于软盘,一个用于 "MBR partitioned" 硬盘,一个用于 "GPT partitioned" 硬盘,一个用于CD,一个用于网络引导)。这些案例完全不同(并且 "one 512-byte initial sector only" 对其中 3 个案例的限制已经足够严格)使 "all devices supported by one boot loader" 想法成为一场灾难。

实际生成ISO;可以使用已有的工具(例如mkisofs),也可以自己写工具(ISO9660和"El Torito"都比较容易理解,自己写工具生成ISO不到2天就搞定,这对于 OS 个开发项目来说就像沧海一粟)。