在程序集 x86 中加载旧的引导加载程序



我正在x86_64架构上用 NASM x86 编写我自己的引导加载程序,对于初学者来说,我只是尝试使用 dd 将现有的引导加载程序复制到第二扇区,然后将其复制回来并从程序集运行它。

文件.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),然后将旧引导加载程序移动到第二扇区。

结果是"从硬盘启动"字符串,这很好,然后我得到"NetBSD MBR 启动" 错误 P",对应于"没有 netBSD 分区"。

编辑:粘贴了错误的asm文件。 第二次编辑:错误已更改,但仍存在。

NetBSD 卷引导记录(NetBSD 称为分区引导记录或 PBR)读取从中引导它的磁盘的第一个块,并检查它是否与自身相同。如果不是,那么它假设磁盘有一个MBR,并尝试在MBR中查找NetBSD引导分区。它通过简单比较加载到内存中的自身的前 4 个字节和磁盘上第一个扇区的前 4 个字节来执行此检查。

由于替换引导扇区不是以完全相同的 4 个字节开头,因此它被解释为带有分区表的 MBR。由于您的引导扇区实际上没有MBR分区表,因此NetBSD VBR无法找到NetBSD分区,因此打印error P(可能或error no slice,取决于它的配置方式)。

要解决此问题,您需要将磁盘的分区表复制到替换 MBR 中。请注意,这也是必要的,因为 NetBSD 本身(或你正在引导的任何内容)也想要读取分区表。

如果您的磁盘没有带有分区表的 MBR,而是从 NetBSD VBR (PBR) 开始,那么您无法解决问题。在这种情况下,当 NetBSD VBR 正常引导时,它会将前 15 个扇区加载到 0000:1000 的内存中,检查前四个字节是否与上述自身匹配,如果是,则跳转到在 0000:1000 加载的代码。由于您正在更改磁盘的前 3 个扇区,因此您还将覆盖扇区 2 处的 NetBSD 磁盘标签,以及 NetBSD 在扇区 3 处称为第 1 阶段引导程序 (bootxx) 的开始。

我可以

毫无问题地在第一个 512B 中塞满所有内容,但是在阅读旧引导加载程序后,我无法再跳到开头

当然,您不能既在 7C00-7DFF 区域中运行,又将其他扇区加载到其中,因此您需要准备一些将在 7C00-7DFF 之外运行的代码,它将原始引导扇区加载到预期的 0000:7C00,并像 BIOS 一样执行它。

我试图修改您的代码以使其像那样工作,但我无法调试/验证它是否有效,因此请谨慎行事(我使用 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

仍然不起作用

好吧,如果没有调试器,你很难在汇编程序中编程,有太多可能出错的地方,每个细节都可能很重要。当你在asm方面有经验时,你可以把它拿出来,但如果你正在学习,那就买一些PC模拟器,你也可以调试一些东西,比如bochs。首先使用文档(就像你的评论incbin,当然在 NASM 文档中描述了它到底做了什么)。

我根据迈克尔的评论调整了源代码,但我仍然没有办法验证/调试它(懒得安装 bochs + 学习如何设置引导加载程序扇区),但代码本身是"好的",它主要是按照评论说的去做。这是否足以或正确启动PC机器,这是另一个问题。它只是解决了相关代码的明显问题,以尝试在 512B 单扇区块之外拥有"第三"部分。

相关内容

  • 没有找到相关文章

最新更新