Есть несколько вещей, которые вам нужно сделать, чтобы это сработало.
Во-первых, вам нужно убедиться, что nasm, gcc и ld создают бинарные файлы macho i386. Это означает передачу -f macho
в nasm, -m32
в gcc и -arch i386
в ld, иначе вы получите x86_64 macho двоичные файлы.
Во-вторых, GRUB не поддерживает двоичные файлы Macho - он поставляется только с готовой поддержкой двоичных форматов ELF. Но это не проблема - вы можете точно сказать GRUB, что делать для загрузки вашего Macho-ядра, используя заголовок мультизагрузки.
В частности, вам нужно установить 16-й бит FLAGS в заголовке мультизагрузки:
FLAGS 1<<16 | whateverelse
Это скажет GRUB взять информацию о том, где загрузить ядро от вас, вместо того, чтобы пытаться выяснить это автоматически.
Теперь вам нужно сообщить GRUB эту информацию. В частности, есть 4 поля, которые нужны GRUB (или любому мультизагрузочному совместимому загрузчику) для загрузки ядра в любом двоичном формате:
header_addr
: Физическая область памяти, в которой ваше ядро будет находиться. Установите его равным адресу раздела .text. (Подсказка: поместите метку сразу после .text и просто обратитесь к ней здесь)
load_addr
: адрес, с которого GRUB должен начать загрузку с диска. В случае с мачо .text является первым адресом, поэтому мы также устанавливаем его в местоположение .text
load_end_addr
: Где GRUB должен прекратить загрузку. Обычно что-то вроде stack+STACKSIZE
будет работать.
bss_end_addr
: Где расположен конец секции BSS. В мачо, это прямо там, в конце, поэтому установка его равным load_end_addr
будет работать.
entry_addr
: точка входа для вашего кода ядра. На OS X это значение по умолчанию start
, хотя согласно этому руководству это loader
.
Мой пример кода для этого:
global start ; making entry point visible to linker
extern _kmain ; kmain is defined elsewhere
; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
MEMINFO equ 1<<1 ; provide memory map
MACHO equ 1<<16
FLAGS equ MODULEALIGN | MEMINFO | MACHO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + FLAGS) ; checksum required
section .text
align 4
MultiBootHeader:
dd MAGIC
dd FLAGS
dd CHECKSUM
dd MultiBootHeader
dd MultiBootHeader
dd stack+STACKSIZE
dd stack+STACKSIZE
dd start
; reserve initial kernel stack space
STACKSIZE equ 0x4000 ; that's 16k.
start:
mov esp, stack+STACKSIZE ; set up the stack
push eax ; pass Multiboot magic number
push ebx ; pass Multiboot info structure
call _kmain ; call kernel proper
cli
hang:
hlt ; halt machine should kernel return
jmp hang
section .bss
align 4
stack:
resb STACKSIZE ; reserve 16k stack on a doubleword boundary
Сделав это, когда вы скажете GRUB загрузить ваше ядро командой kernel 200+x
, вы увидите всплывающее сообщение «multiboot-kludge» с информацией о том, откуда все будет загружено. Ввод boot
загрузит ваше ядро macho, и вы будете настроены!