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
Директива рассчитает правильное выравнивание для вас. Это делает код более понятным.