x86 - multiboot2 标头正确进入“启用了启动服务的 EFI amd64 机器状态”-hlt 指令不起作用?
问题描述
我有一个基本start.asm
(nasm 汇编器)的简单设置和一个multiboot2_header.asm
在编译后链接在一起的。multiboot2 标头位于最终文件的开头ELF64-x86_64
。要运行它,我使用QEMU -> OVMF (UEFI) -> GRUB -> <my-binarỳ>
. 当我使用最小的 multiboot2 标头时,一切正常:我处于 32 位模式,我可以设置自己的堆栈和调用函数。为了验证这一点,我检查了 QEMU 中的寄存器。但是现在我想启动到EFI amd64 machine state with boot services enabled
第3.5节multiboot2 规范 [ 1 ] 中定义的 ,但这会导致问题。
我如何尝试实现我的目标:
规范说明,multiboot2 标头必须包含两个标签EFI boot services tag: leaves UEFI boot services enabled
和EFI amd64 entry address tag of Multiboot2 header tag
. 我有信心我做对了(下面的代码)。
问题(更新 2021-06-17)
经过更多调查,看起来我的方法大部分(?)是正确的。问题是,我的hlt
指令被忽略了。这样,执行的代码比预期的要多,一些执行中毒eax
。如果我将hlt
起始符号jmp
中jmp
的 (更新结束)eax
multiboot2-header.asm:
; This file uses "Netwide Assembler Syntax" and can be compiled by running
; `nasm -f elf64 multiboot2_header.asm -o multiboot2_header.o`
;
; External symbol, that comes "start.asm"
EXTERN start
ALIGN 8 ; according to spec, the header must be 64-bit (8 byte) aligned
section .multiboot_header
header_start:
; dd => int 32, see https://www.cs.uaf.edu/2017/fall/cs301/reference/x86_64.html
dd 0xe85250d6 ; magic number (multiboot 2 spec)
dd 0 ; architecture 0 (protected mode i386; spec doesn't specify many options)
dd header_end - header_start ; header length
; checksum
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
; OPTIONAL MULTIBOOT2 TAGS (additional to required END TAG)
; In order to boot into "EFI amd64 machine state with boot services enabled" (3.5 in Spec, 2021-06)
; machine state, we must specify a few additional tags:
;
; ------------------------------------------------------------------------------------
; "EFI boot services tag": leaves UEFI boot services enabled: its our task to exit them
ALIGN 8 ; alignment in bits, according to multiboot2 spec, tags are 8-byte (64bit) aligned
dw 7 ; type (16bit)
dw 0 ; flags (16bit)
dd 8 ; size (32bit)
; ------------------------------------------------------------------------------------
; "EFI amd64 entry address tag of Multiboot2 header tag"
ALIGN 8
dw 9 ; type (16bit)
dw 0 ; flags (16bit)
dd 12 ; size (32bit)
; TODO I'm not entirely sure how this works together with the "start" symbol from the linker script:
; perhaps the start symbol in the linker script is a fallback, if this is not found
dd start ; entry_addr (32bit)
; ------------------------------------------------------------------------------------
; REQUIRED END TAG
ALIGN 8
dw 0 ; type (16bit)
dw 0 ; flags (16bit)
dd 8 ; size (32bit)
header_end:
PS:Rust 工具 bootinfo [ 2 ] 可以正确识别我最终 ELF 中的 multiboot2 标头和指定标签。
解决方案
我最初的方法是正确的,实际上是正确的。由于两个误解,我无法正确检查:
- 我实际上处于 64 位长模式,但尝试执行 32 位代码
hlt
指令不起作用,因为 QEMU 有一些中断并且hlt
被清除了
如果启动符号如下所示,您可以在启动期间/切换后轻松验证 QEMU 中的寄存器:
GLOBAL start
SECTION .text
; produce x-bit x86 code (even if this will be an ELF-64 file)
[BITS 64]
start:
mov r12, 0xffffeeeeddddcccc ; verify that we are in 64-bit mode (otherwise this fails)
cli ; without clear interrupts, the hlt is ignored (I don't know what interrupt comes.. maybe the key input in qemu)
hlt
推荐阅读
- jsrender - 将值从外部传递到内部以使用 jsRender
- swift - 在 Swift 中使用 NSRegularExpression 将字符串替换为子字符串
- kubernetes - 无法使用 Oracle 云生成的默认配置文件登录
- python - Tensorflow:对张量进行分桶,然后产生分类张量
- c# - 对数据库中非空列的查询排序
- python-3.x - anaconda 上的 jupyter 笔记本 - “win32security”内核错误
- python - 如何使用python从块中索引整个矩阵
- java - 未能在项目 blazegraph-service 上执行目标:
- git - git config --global 或 git push 不起作用。Bitbucket 相关
- php - 使用 SetAutoPageBreak 多单元格值分页后的 FPDF 未插入到定义的 Y 位置