在程序集 x86 中加载旧引导加载程序
Loading old bootloader in assembly x86
我正在 NASM x86 中 x86_64 架构上编写自己的引导加载程序,对于初学者来说,我只是尝试使用 dd 将现有的引导加载程序复制到第二个扇区,然后将其复制回来并 运行 它来自汇编。
file.asm
org 0x7c00
jmp 0:start
start:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x8000
mov ah, 0x02
mov al, 1
mov dl, 0x80
mov ch, 0
mov dh, 0
mov cl, 3
mov bx, 0x7e00
int 0x13
jmp 0x7e00
times 510-($-$$) db 0
dw 0xaa55
times (1024 - ($ - $$)) db 0x00
third_sector:
mov ah, 0x02
mov al, 1
mov dl, 0x80
mov ch, 0
mov dh, 0
mov cl, 2
mov bx, 0x7c00
int 0x13
jmp 0x7c00
代码设置堆栈,然后用零将自身拍到 1024 字节以在磁盘的第三个扇区中拥有最后一位代码,然后将磁盘的第二个扇区加载到第一个扇区并跳转到第一个扇区。
src.sh
#!/bin/bash
dd bs=1 count=512 if=/dev/c0d0 of=tmp
nasm -f bin file.asm -o file
dd bs=1 count=1200 if=file of=/dev/c0d0
dd bs=1 count=512 seek=512 if=tmp of=/dev/c0d0
我正在做的是将原始引导加载程序复制到名为 tmp 的临时文件中,然后编译我的程序并将其放入旧引导加载程序的位置(/dev/c0d0 因为我正在使用 MINIX 3.3.0),然后移动旧的引导加载程序进入第二扇区。
结果是"Booting from hard disk"字符串,没问题,然后我得到“NetBSD MBR boot
错误 P" 对应 "no netBSD partition".
编辑:粘贴了错误的 asm 文件。
第二次编辑:错误已更改,但仍然存在。
I can cram everything in first 512B without trouble, but then after reading the old bootloader I can no longer jump to the beginning
当然你不能既运行在7C00-7DFF区域,又加载其他扇区进去,所以你需要准备一些代码,运行在外面7C00-7DFF,它会将原始引导扇区加载到预期的0000:7C00,并像BIOS一样执行。
我试图修改你的代码以使其像那样工作,但我无法 debug/verify 如果它有效,所以请谨慎行事(我使用 ndisasm 反汇编生成的二进制文件,一切看起来都正常,即.重定位的代码不依赖于它的地址,所以你可以自由地将它移动到任何内存,它应该加载+执行那个扇区到7C00。
只要确保您没有向该代码添加任何内容,搬迁到 7e00 后会出现什么问题。
org 0x7c00
jmp 0:start
start:
mov ax, cs ; ax = 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, ax ; ss:sp = 0:0
; relocate second boot loader code outside of 7C00-7DFF (to 7E00)
mov si, boot_loader_code ; address of code to relocate
mov di, 0x7e00 ; new address of code
mov cx, boot_loader_code_length
cld
rep movsb
; execute the relocated second boot loader
jmp 0x7e00
boot_loader_code:
; load second boot loader to 0:7c00 and execute it
mov ah, 0x02 ; load sector service
mov al, 1 ; load 1 sector
; mov dl, 0x80 ; drive 0
; DL is set by BIOS originally
; and this code did/will not change it
mov ch, 0 ; track/cylinder
mov dh, 0 ; head number
mov cl, 3 ; sector number
mov bx, 0x7c00 ; es:bx pointer to buffer
int 0x13 ; BIOS "load sector" service
jmp 0:0x7c00
boot_loader_code_length EQU ($ - boot_loader_code)
times 510-($-$$) db 0
dw 0xaa55
still isn't working
好吧,如果没有调试器,你很难用汇编程序编程,可能出错的地方太多了,每个细节都可能很重要。当你对 asm 有经验时,你可以把它拉出来,但如果你正在学习,得到一些 PC 模拟器,在那里你也可以调试东西,比如 bochs。并首先使用文档(比如您的 incbin
评论,它在 NASM 文档中有所描述,当然,它到底做了什么)。
我根据Michael的评论调整了源码,但我还是没办法verify/debug它(懒得安装bochs +学习如何设置bootloader扇区),但代码本身是"ok",它主要做评论所说的。这对于启动 PC 机器是否足够或是否正确,那是另一个问题。它只是修复了您的代码中试图将 "third" 部分置于 512B 单扇区块之外的明显问题。
NetBSD 卷引导记录(NetBSD 称为分区引导记录或 PBR)读取它引导的磁盘的第一个块并检查它是否与它自己相同。如果不是,那么它假定磁盘有一个 MBR 并尝试在 MBR 中找到 NetBSD 引导分区。它通过简单比较加载到内存中的自身的前 4 个字节和磁盘上第一个扇区的前 4 个字节来进行检查。
由于您的替换引导扇区不是以完全相同的 4 字节开始,因此它被解释为具有分区 table 的 MBR。由于您的引导扇区实际上没有 MBR 分区 table,因此 NetBSD VBR 无法找到 NetBSD 分区,因此打印 error P
(可能是 error no slice
,具体取决于它如何已配置)。
要解决此问题,您需要将磁盘分区 table 复制到替换 MBR 中。请注意,这也是必要的,因为 NetBSD 本身(或您正在引导的任何东西)也需要读取分区 table.
如果您的磁盘没有带分区 table 的 MBR,而是从 NetBSD VBR (PBR) 开始,那么您无法解决此问题。在这种情况下,当 NetBSD VBR 正常启动时,它将前 15 个扇区加载到位于 0000:1000 的内存中,如上所述检查前四个字节是否与自身匹配,如果匹配则跳转到 [=20= 处加载的代码].由于您正在更改磁盘的前 3 个扇区,因此您还覆盖了扇区 2 处的 NetBSD 磁盘标签以及扇区 3 处 NetBSD 称为阶段 1 bootstrap (bootxx) 的开始。
我正在 NASM x86 中 x86_64 架构上编写自己的引导加载程序,对于初学者来说,我只是尝试使用 dd 将现有的引导加载程序复制到第二个扇区,然后将其复制回来并 运行 它来自汇编。
file.asm
org 0x7c00
jmp 0:start
start:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x8000
mov ah, 0x02
mov al, 1
mov dl, 0x80
mov ch, 0
mov dh, 0
mov cl, 3
mov bx, 0x7e00
int 0x13
jmp 0x7e00
times 510-($-$$) db 0
dw 0xaa55
times (1024 - ($ - $$)) db 0x00
third_sector:
mov ah, 0x02
mov al, 1
mov dl, 0x80
mov ch, 0
mov dh, 0
mov cl, 2
mov bx, 0x7c00
int 0x13
jmp 0x7c00
代码设置堆栈,然后用零将自身拍到 1024 字节以在磁盘的第三个扇区中拥有最后一位代码,然后将磁盘的第二个扇区加载到第一个扇区并跳转到第一个扇区。
src.sh
#!/bin/bash
dd bs=1 count=512 if=/dev/c0d0 of=tmp
nasm -f bin file.asm -o file
dd bs=1 count=1200 if=file of=/dev/c0d0
dd bs=1 count=512 seek=512 if=tmp of=/dev/c0d0
我正在做的是将原始引导加载程序复制到名为 tmp 的临时文件中,然后编译我的程序并将其放入旧引导加载程序的位置(/dev/c0d0 因为我正在使用 MINIX 3.3.0),然后移动旧的引导加载程序进入第二扇区。
结果是"Booting from hard disk"字符串,没问题,然后我得到“NetBSD MBR boot 错误 P" 对应 "no netBSD partition".
编辑:粘贴了错误的 asm 文件。 第二次编辑:错误已更改,但仍然存在。
I can cram everything in first 512B without trouble, but then after reading the old bootloader I can no longer jump to the beginning
当然你不能既运行在7C00-7DFF区域,又加载其他扇区进去,所以你需要准备一些代码,运行在外面7C00-7DFF,它会将原始引导扇区加载到预期的0000:7C00,并像BIOS一样执行。
我试图修改你的代码以使其像那样工作,但我无法 debug/verify 如果它有效,所以请谨慎行事(我使用 ndisasm 反汇编生成的二进制文件,一切看起来都正常,即.重定位的代码不依赖于它的地址,所以你可以自由地将它移动到任何内存,它应该加载+执行那个扇区到7C00。
只要确保您没有向该代码添加任何内容,搬迁到 7e00 后会出现什么问题。
org 0x7c00
jmp 0:start
start:
mov ax, cs ; ax = 0
mov ds, ax
mov es, ax
mov ss, ax
mov sp, ax ; ss:sp = 0:0
; relocate second boot loader code outside of 7C00-7DFF (to 7E00)
mov si, boot_loader_code ; address of code to relocate
mov di, 0x7e00 ; new address of code
mov cx, boot_loader_code_length
cld
rep movsb
; execute the relocated second boot loader
jmp 0x7e00
boot_loader_code:
; load second boot loader to 0:7c00 and execute it
mov ah, 0x02 ; load sector service
mov al, 1 ; load 1 sector
; mov dl, 0x80 ; drive 0
; DL is set by BIOS originally
; and this code did/will not change it
mov ch, 0 ; track/cylinder
mov dh, 0 ; head number
mov cl, 3 ; sector number
mov bx, 0x7c00 ; es:bx pointer to buffer
int 0x13 ; BIOS "load sector" service
jmp 0:0x7c00
boot_loader_code_length EQU ($ - boot_loader_code)
times 510-($-$$) db 0
dw 0xaa55
still isn't working
好吧,如果没有调试器,你很难用汇编程序编程,可能出错的地方太多了,每个细节都可能很重要。当你对 asm 有经验时,你可以把它拉出来,但如果你正在学习,得到一些 PC 模拟器,在那里你也可以调试东西,比如 bochs。并首先使用文档(比如您的 incbin
评论,它在 NASM 文档中有所描述,当然,它到底做了什么)。
我根据Michael的评论调整了源码,但我还是没办法verify/debug它(懒得安装bochs +学习如何设置bootloader扇区),但代码本身是"ok",它主要做评论所说的。这对于启动 PC 机器是否足够或是否正确,那是另一个问题。它只是修复了您的代码中试图将 "third" 部分置于 512B 单扇区块之外的明显问题。
NetBSD 卷引导记录(NetBSD 称为分区引导记录或 PBR)读取它引导的磁盘的第一个块并检查它是否与它自己相同。如果不是,那么它假定磁盘有一个 MBR 并尝试在 MBR 中找到 NetBSD 引导分区。它通过简单比较加载到内存中的自身的前 4 个字节和磁盘上第一个扇区的前 4 个字节来进行检查。
由于您的替换引导扇区不是以完全相同的 4 字节开始,因此它被解释为具有分区 table 的 MBR。由于您的引导扇区实际上没有 MBR 分区 table,因此 NetBSD VBR 无法找到 NetBSD 分区,因此打印 error P
(可能是 error no slice
,具体取决于它如何已配置)。
要解决此问题,您需要将磁盘分区 table 复制到替换 MBR 中。请注意,这也是必要的,因为 NetBSD 本身(或您正在引导的任何东西)也需要读取分区 table.
如果您的磁盘没有带分区 table 的 MBR,而是从 NetBSD VBR (PBR) 开始,那么您无法解决此问题。在这种情况下,当 NetBSD VBR 正常启动时,它将前 15 个扇区加载到位于 0000:1000 的内存中,如上所述检查前四个字节是否与自身匹配,如果匹配则跳转到 [=20= 处加载的代码].由于您正在更改磁盘的前 3 个扇区,因此您还覆盖了扇区 2 处的 NetBSD 磁盘标签以及扇区 3 处 NetBSD 称为阶段 1 bootstrap (bootxx) 的开始。