为啥我的引导加载程序无法在最近的笔记本电脑上运行?
Posted
技术标签:
【中文标题】为啥我的引导加载程序无法在最近的笔记本电脑上运行?【英文标题】:Why is my bootloader not working on recent laptops?为什么我的引导加载程序无法在最近的笔记本电脑上运行? 【发布时间】:2019-09-29 22:31:52 【问题描述】:我想从头开始做一个简单的引导加载程序。我希望它能够在最近的笔记本电脑上通过 USB 启动,这意味着它具有 UEFI 启动但理论上它支持 Legacy 启动。
所以我写了一小段汇编代码,它只打印“hello world”,然后用 nasm -f bin boot.asm -o boot.com 编译它 然后我用 dd 从二进制文件构建了软盘。 该软盘在 qemu-system-x86_64 上运行良好。我使用 dd if=boot.bin of=/dev/sda 将其传输到格式化为 FAT32 的 U 盘的 MBR。 但是当用我最近的电脑启动它时,USB 没有出现在可启动设备中。
我试图: - 在 Qemu 上成功启动它(使用 qemu-system-x86_64 -hdb /dev/sda) - 在具有英特尔奔腾 4 处理器的非常旧的计算机上启动它,一切都按预期工作。 - 在 Bios 选项中启用传统模式 - 禁用安全启动 - 在另一台计算机上启动它,USB 棒显示在可启动设备中,但没有打印任何内容。
我在网上找到的,所以组装应该是正确的
;; A tiny, working bootloader for x86 PCs. Has a few subroutines
;; so it's slightly less useless than just printing "hello world".
;;
;; writeup here: http://joebergeron.io/posts/post_two.html
;;
;; Joe Bergeron, 2016.
;;
bits 16
mov ax, 07C0h
mov ds, ax
mov ax, 07E0h ; 07E0h = (07C00h+200h)/10h, beginning of stack segment.
mov ss, ax
mov sp, 2000h ; 8k of stack space.
call clearscreen
push 0000h
call movecursor
add sp, 2
push msg
call print
add sp, 2
cli
hlt
clearscreen:
push bp
mov bp, sp
pusha
mov ah, 07h ; tells BIOS to scroll down window
mov al, 00h ; clear entire window
mov bh, 07h ; white on black
mov cx, 00h ; specifies top left of screen as (0,0)
mov dh, 18h ; 18h = 24 rows of chars
mov dl, 4fh ; 4fh = 79 cols of chars
int 10h ; calls video interrupt
popa
mov sp, bp
pop bp
ret
movecursor:
push bp
mov bp, sp
pusha
mov dx, [bp+4] ; get the argument from the stack. |bp| = 2, |arg| = 2
mov ah, 02h ; set cursor position
mov bh, 00h ; page 0 - doesn't matter, we're not using double-buffering
int 10h
popa
mov sp, bp
pop bp
ret
print:
push bp
mov bp, sp
pusha
mov si, [bp+4] ; grab the pointer to the data
mov bh, 00h ; page number, 0 again
mov bl, 00h ; foreground color, irrelevant - in text mode
mov ah, 0Eh ; print character to TTY
.char:
mov al, [si] ; get the current char from our pointer position
add si, 1 ; keep incrementing si until we see a null char
or al, 0
je .return ; end if the string is done
int 10h ; print the character if we're not done
jmp .char ; keep looping
.return:
popa
mov sp, bp
pop bp
ret
msg: db "Oh boy do I sure love assembly!", 0
times 510-($-$$) db 0
dw 0xAA55
我希望能够在我最近的计算机上启动 USB,运行 i7-8550U 处理器和 UEFI/Legacy 兼容。 目前,USB 记忆棒并未出现在可启动设备中。
编辑: 谢谢您的回复 ! 我尝试通过添加这段代码来设置 Bios 参数块 (BPB):
ORG 0
BITS 16
jmp near start
db "MYBOOT "
dw 512
db 1
dw 1
db 2
dw 512
dw 65535
db 0xf8
dw 20
dw 63
dw 16
dd 0
dd 0
db 0x29
dd 0xffff
db 0
db 0
db "NO NAME "
db "FAT32 "
start:
blablabla (see above)
USB 棒现在出现在 ubuntu 桌面上(我注意到如果我使用“jmp near start”以外的其他东西,比如“jmp short start”,它就会消失) 但它仍然不想出现在我的 BIOS 启动菜单中。 我真的不知道为什么它现在不想看到它。 我有 F.23 版的 Bios,也许这个 bios 有什么特殊的方法可以做到这一点?
【问题讨论】:
并非您在 Internet 上找到的所有内容都是正确的 :) 请参阅 duplicate 如何使用 BPB 创建引导扇区。这可能会解决您的问题。 首先,您是将 USB 引导为软盘驱动器 (FDD) 仿真或硬盘驱动器磁盘仿真 (HDD)。您应该能够在 USB 相关启动的 BIOS 中看到此设置。我假设从您的 QEMU 命令行中您正在 LInux 上进行开发? 您有机会试用当前答案中的代码吗? 【参考方案1】:我不能将其放在评论中,如果有任何帮助,我会修改它以成为正确的答案。提供的代码实际上也可能是解决问题的方法。这是基于几个月前在OSDev Forum discussion 上发现的类似情况下使用较新的 BIOS。
您能否尝试使用它编译和构建 MBR,并查看您的 BIOS 是否将驱动器识别为可引导驱动器?如果您碰巧在分区媒体上启动,它包含一个自引用分区表。不确定您的 BIOS 正在模拟什么 USB 介质,希望您简单地测试一下它是否可以打印:
你好,世界!
代码:
bits 16
org 0x7c00
boot_start:
xor ax, ax ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00
mov ds, ax
mov es, ax
; If you will be reading data into memory outside of 0x7c00 to 0x7dff
; then you want to set the stack SS:SP - uncomment these lines
; mov ss, ax ; Stack at 0x0000:0x7c00
; mov sp, 0x7c00 ; Just below bootloader
cld ; Forward movement of string instructions
; (MOVSB, SCASB, etc)
mov si, HelloWorldMsg ; Print hello world
call print_string
end_loop: ; Loop forever to terminate
hlt
jmp end_loop
; Function: print_string
; Display a string to the console on display page 0
;
; Inputs: SI = Offset of address to print
; Clobbers: AX, BX, SI
print_string:
mov ah, 0x0e ; BIOS tty Print
xor bx, bx ; Set display page to 0 (BL)
jmp .getch
.repeat:
int 0x10 ; print character
.getch:
lodsb ; Get character from string
test al,al ; Have we reached end of string?
jnz .repeat ; if not process next character
.end:
ret
HelloWorldMsg: db "Hello, world!", 0x0d, 0x0a, 0
times 446-($-$$) db 0 ; Pad with 0s up until first partition entry
part1_entry:
db 0x80 ; 0x80 = Active boot partition, 0x00=inactive
db 0x00, 0x01, 0x00 ; CHS of first absolute sector (MBR) of hard drive
; Head=0, Sector=1, Cylinder=0
db 0x0c ; Partition type (has to be non-zero)
; 0x0c = Win 95 FAT32 (LBA)
db 0x00, 0x01, 0x00 ; CHS of last absolute sector (MBR) of hard drive
; Head=0, Sector=1, Cylinder=0
; We are effectively saying Size of partition is 1 sector
dd 0x0 ; LBA of first absolute sector (0=MBR)
dd 0x1 ; Number of sectors in partition. We set it to 1 but if you
; wish you could set it to the number of sectors on the disk
times 510-($-$$) db 0 ; Pad remainder of boot sector up to boot signature. This zeroes
; partition entries 2,3,4 effectively making them inactive
dw 0xAA55 ; The standard PC boot signature after partition table
此代码可能不会使您的驱动器可见,甚至无法启动和输出任何内容,但结果可以帮助缩小问题范围。考虑到您的 BIOS 的反应,我的一部分认为可能不仅仅是 BPB 问题。
【讨论】:
这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review @Rob :问题在于,要缩小问题的范围非常困难,因为这样做实际上需要提供不适合注释的代码级别。这实际上是一个很好的问题,希望通过 OP 的一些输入和测试,这个问题可以 a)正确复制另一个问题,或者 b)这个非答案可以作为涉及分区媒体的解决方案的潜在字符串点。与许多琐碎的问题不同,对于尚未在 So 上捕捉到的棘手问题,有一个潜在的机会来回答。 我相信你的话,这是评论而不是问题的答案,但答案部分不允许使用 cmets。 我知道这不属于典型的解决方案,但它实际上可能是一个解决方案。我们只能知道 OP 是否取得了一些成功。这是一个非答案,我愿意接受成堆的反对票而不是删除,希望它最终可以变成有用的东西。 @rob :这个问题中的代码实际上可能是解决方案。他可能只需要一个自引用分区表来欺骗 BIOS。该代码实际上是一个完整的功能 MBR,它打印 hello world。如果可行,这可以很容易地转化为带有解释的正确答案。在这种情况下,如果您对该主题知之甚少,它可能看起来一无所有,但我是 [bootloader] 标签中排名最高的回答者之一。我希望评论者可以放纵我。这有可能成为规范的问答。我会尊重投票并希望答案可以避免此时被删除以上是关于为啥我的引导加载程序无法在最近的笔记本电脑上运行?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的笔记本上安装RStudio运行不了,一打开就出现下面的错误
“无法加载文件或程序集”错误。可以在我的电脑上运行,但不能在其他电脑上运行