You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Multiboot2标签遍历遇无效标签及请求被忽略问题咨询

关于Multiboot2标签遍历与type=25标签的问题

我在基于GRUB2实现Multiboot2兼容的操作系统启动时,遍历GRUB2提供的标签时遇到两个问题:

  • 收到了type=25的标签
  • 请求的type=6(内存映射标签)被忽略
    不确定当前的标签遍历方法是否正确,也想了解type=25标签的相关信息。

相关代码

multiboot2.asm

;; multiboot2.asm

%define mb2_magic 0xE85250D6
%define mb2_arch 0

section .boot
_mb2:
dd mb2_magic
dd mb2_arch
dd _emb2 - _mb2
dd 0x100000000 - (mb2_magic + mb2_arch + (_emb2 - _mb2))

align 8

.mb2_ir:
    dw 1 ; information request
    dw 0
    dd .emb2_ir - .mb2_ir
    dd 6 ; memory map tag
.emb2_ir:

align 8

.end_tag:
    dd 0
    dd 8
_emb2:

entry.asm

;entry.asm

[BITS32]
__start:
    mov [.mb2_magic], eax
    mov [.mb2_info], ebx
    ;; ...
    call check_multiboot
    ;; ...
    lgdt [gdt64.ptr]
    jmp gdt64.code:realm64
    .mb2_magic:
        dd 0
    .mb2_info:
        dq 0

check_multiboot:
    mov eax, [__start.mb2_magic]
    cmp eax, 0x36D76289 ; multiboot2 magic number
    jne .fail
    ret
    .fail:
        mov ebx, .message
        call quick_print ; defined in file
        hlt
    .message:
        db "Boot Check Failed:", 0x0A, 0x0A, "Was not booted from MultiBoot2", 0x0A, "MBR (Master Boot Record) is incompatible", 0x00

;; ...
[BITS 64]
realm64:
    ;; ...
    [extern main]
    mov rsi, [__start.mb2_magic]
    mov rdi, [__start.mb2_info]
    call main

kernel.c

// kernel.c

int main(mb2_info_header* mbd, uint32_t magic) // magic checked in entry.asm
{
    tty_init();
    mb2_traverse(mbd);
    // ...
}

multiboot2.c

// multiboot2.c

typedef struct s_MB2_tag {
    uint32_t type;
    uint32_t size;
} mb2_tag;

typedef struct s_MB2_info_header {
    uint32_t total_size;
    uint32_t __RSV1;
} mb2_info_header;

void mb2_traverse(mb2_info_header *mbd)
{
    uint64_t mb2_end = mbd->total_size + (uint64_t)mbd;
    mb2_tag *tag = (mb2_tag*)(mbd + sizeof(mb2_info_header));
    while ((uint64_t)tag < mb2_end)
    {
        tty_printf("TAG %d\t[%d] @\t%x\n", tag->type, tag->size, tag);
        if (tag->type == 0)
            break;
        tag += tag->size;
        if ((uint64_t)tag & 0x7)
            tag += 8 - ((uint64_t)tag & 0x7);
    }
}

运行输出:

TAG N  [size] @  ptr

问题分析与解决

1. 标签遍历方法的错误

你的mb2_traverse函数中,tag += tag->size这一步存在致命错误:tag是指针类型,直接做加法会让指针偏移tag->size * sizeof(mb2_tag)字节,而不是tag->size字节(标签的size字段单位是字节)。这会导致遍历逻辑完全混乱,跳过正确标签甚至越界读取到错误的type值(比如type=25)。

正确的偏移方式是将指针转换为整数类型后再计算:

tag = (mb2_tag*)((uintptr_t)tag + tag->size);

2. type=25标签的说明

type=25是GRUB2自定义的EFI系统表标签,属于Multiboot2规范中"实现定义"的标签(规范规定type 10及以上为私有扩展)。仅当GRUB2在EFI模式下启动时才会生成该标签,用于传递EFI系统表的指针。如果你的操作系统不需要EFI相关功能,可以直接忽略这个标签。

3. 内存映射标签被忽略的原因

修复遍历逻辑后,应该能正常读取到type=6的内存映射标签。另外确认你的Multiboot2信息请求格式正确——你代码中mb2_ir部分的请求是合法的,指定了需要内存映射标签。


修复后的遍历函数

void mb2_traverse(mb2_info_header *mbd)
{
    uintptr_t mb2_end = (uintptr_t)mbd + mbd->total_size;
    mb2_tag *tag = (mb2_tag*)((uintptr_t)mbd + sizeof(mb2_info_header));
    
    while ((uintptr_t)tag < mb2_end)
    {
        tty_printf("TAG %d\t[%d] @\t%x\n", tag->type, tag->size, (uintptr_t)tag);
        
        if (tag->type == 0) // 终止标签,退出遍历
            break;
            
        // 正确偏移到下一个标签的起始位置
        tag = (mb2_tag*)((uintptr_t)tag + tag->size);
        
        // 确保标签地址8字节对齐
        if ((uintptr_t)tag & 0x7)
            tag = (mb2_tag*)((uintptr_t)tag + (8 - ((uintptr_t)tag & 0x7)));
    }
}

内容的提问来源于stack exchange,提问作者IsCoffeeTho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:09:53