GNU GRUB выдает "ошибка: неподдерживаемый тег: 0xc" для Multiboot2

Я попытался использовать следующий код для заголовка совместимого с Multiboot2 ядра, но когда я попытался multiboot2 Команда в grub выдала следующее сообщение об ошибке:

ошибка: неподдерживаемый тег: 0xc

Мой заголовок Multiboot2 определяется как:

section .multiboot align=4096
mbhead: dd 0xe85250d6
        dd 0
        dd 76
        dd 0 - 76 - 0xe85250d6                  ; TODO the linker and assembler get angry if we calculate this with symbols, we need to do this by hand
        dw 1                                    ; multiboot information request
        dw 0
        dd 20
        dd 1
        dd 2
        dd 6
        dw 4                                    ; console flags
        dw 0
        dd 12
        dd 0x3
        dw 5                                    ; framebuffer settings
        dw 1
        dd 12
        dd 80
        dd 25
        dd 0
        dw 0                                    ; last tag
        dw 0
        dd 8

Мой репозиторий проекта предоставляет полный исходный код. Я генерирую ISO с make test_longmode.iso, Я тестирую с QEMU.

В чем проблема, вызывающая ошибку тега, и как я могу ее исправить?

1 ответ

Решение

Основные проблемы

Ошибка GRUB:

ошибка: неподдерживаемый тег: 0xc

Это потому, что вы не выровняли каждый тег по 8 байт согласно спецификации Multiboot2:

3.1.3 Общая структура тегов

Теги представляют собой буфер структур, следующих друг за другом, дополненных при необходимости, чтобы каждый тег начинался с 8-байтового выровненного адреса. Теги заканчиваются тегом типа "0" и размером "8". Каждая структура имеет следующий формат

Чтобы легко это исправить, вы можете использовать align 8 перед каждым тегом, и вы можете позволить ассемблеру обработать выравнивание. Это выравнивание не вычисляется по длине тега.

Ваша контрольная сумма может быть лучше рассчитана, чтобы не вызывать предупреждение, если NASM использует усечение. Эта строка:

dd 0 - 76 - 0xe85250d6

Можно было бы лучше выразить как:

dd 0x100000000 - 76 - 0xe85250d6

Читаемость кода

Я думаю, что первое, что есть в этом фрагменте кода, это то, насколько он нечитабелен. Что привлекло мое внимание, так это комментарий:

TODO компоновщик и ассемблер рассердятся, если мы вычислим это с помощью символов, нам нужно сделать это вручную

Возможно, вы вычислили значения вручную, потому что у вас была проблема с попыткой сделать это каким-либо другим способом. Директива NASM, которая здесь помогает, это директива EQU:

3.2.4 EQU: определение констант

EQU определяет символ для данного постоянного значения: когда используется EQU, строка источника должна содержать метку. Действие EQU состоит в том, чтобы определить данное имя метки для значения его (единственного) операнда. Это определение является абсолютным и не может измениться позже. Так, например,

message         db      'hello, world' 
msglen          equ     $-message

определяет msglen как постоянную 12. msglen не может быть затем переопределен позже. Это также не определение препроцессора: значение msglen оценивается один раз, используя значение $ (объяснение $ см. В разделе 3.5) в точке определения, а не вычисляется там, где на него ссылаются, и используя значение $ в точке отсчета.

Используя EQU, мы можем сделать код более читабельным.

Во-вторых, вы можете добавить метки в начало и конец каждого тега, а затем ассемблер вычислит для вас длину каждого тега. Длина - это разница между конечной меткой и начальной меткой для каждого тега.


Улучшенный код

Код сборки NASM с предложенными выше изменениями может выглядеть следующим образом:

MB2_ARCH  EQU 0                                 ; 0 = x86/x86-64
MB2_LEN   EQU (mbend-mbhead)
MB2_MAGIC EQU 0xe85250d6

section .multiboot align=4096
mbhead:
        dd MB2_MAGIC                            ; Multiboot2 magic number
        dd MB2_ARCH                             ; Architecture
        dd MB2_LEN                              ; Multiboot header length
        dd 0x100000000 - MB2_LEN - MB2_ARCH - MB2_MAGIC
                                                ; Checksum

mb2_tag_info_start:
        dw 1                                    ; multiboot information request
        dw 0
        dd mb2_tag_info_end - mb2_tag_info_start
        dd 1
        dd 2
        dd 6
mb2_tag_info_end:

        align 8
mb2_tag_console_start:
        dw 4                                    ; console flags
        dw 0
        dd mb2_tag_console_end - mb2_tag_console_start
        dd 0x3
mb2_tag_console_end:

        align 8
mb2_tag_fb_start:
        dw 5                                    ; framebuffer settings
        dw 1
        dd mb2_tag_fb_end - mb2_tag_fb_start
        dd 80
        dd 25
        dd 0
mb2_tag_fb_end:

        align 8
mb2_tag_end_start:
        dw 0                                    ; last tag
        dw 0
        dd mb2_tag_end_end - mb2_tag_end_start
mb2_tag_end_end:

mbend:

Это может быть улучшено в дальнейшем, но даже это будет казаться более читабельным и самодокументированным, чем оригинальный фрагмент кода. Если вы измените размер тега или заголовка, все длины будут вычислены для вас. Если размер изменяет align 8 Директива рассчитает правильное выравнивание для вас. Это делает код более понятным.

Другие вопросы по тегам