загрузчик ядра в эмуляторе qemu

Добрый день, уважаемые читатели. В статье я расскажу про процесс включения компьютера с процессором на базе архитектуры x86 и про загрузчик ядра. Как только электричество подалось на плату в оперативную память загружается специальная программа, хранящаяся в ПЗУ, под названием BIOS. Эта аббревиатура расшифровывается Basic Input Output System или, если на русском языке, базовая система ввода-вывода.

BIOS выполняет несколько задач:

  • Проверка оборудования
  • Настройка оборудования
  • Предоставление программных интерфейсов для работы с оборудованием
  • Загрузка ядра операционной системы

Пропустим три пункта и сразу перейдем к последнему.

Сначала, конечно, BIOS должна найти загрузчик операционной системы на всех указанных носителях и в порядке очереди. Упростим ситуацию и будем считать, что из устройств у нас есть только один диск.

Для определения что диск является загрузочным система читает первый сектор (цилиндр 0, головка 0, сектор 0).

схема устройства жесткого диска

Размер сектора равен 512 байт. Если 511 байт равен 0x55, а 512 – 0xAA, то значит данный диск загрузочный. После этого BIOS передает управление на адрес начала, загруженного сектора. 0x55AA – магическое число!

(Я всегда знал, что без магии не обошлось!!!)

загрузчик ядра в машинных кодах

Это простейший загрузочный сектор в машинных кодах. Трудновато читать. Покажу как этот код выглядит в ассемблере:

; Бесконечный цикл (e9 fd ff)
loop:
    jmp loop 

; Заполнить (510 - размер предыдущего кода) байт нулями
times 510-($-$$) db 0
; Магическое число
dw 0xAA55

Комментарии очевидны и говорят сами за себя. Программа при запуске, загрузчик ядра покажет экран, примерно похожий на тот, который в заголовке статьи. После этого зависнет.

Отлично! Может быть стоит сделать что-нибудь более интересное. Например поздороваться со всем миром! 🙂 Программисты очень любят это делать.

org 0x7c00

mov bx, HELLO
start:
    mov al, [bx] 
    cmp al, 0 
    je done

    mov ah, 0x0E
    int 0x10 

    add bx, 1
    jmp start

done:
    jmp $

HELLO: 
    db 'Hello, World!', 0

times 510 - ($-$$) db 0
dw 0xAA55

Количество строк увеличилось, но сложности, по существу, это не добавило. Посмотрим что делает этот код.

В регистр bx помещается адрес первого символа текстовой строки. Я пометил ее меткой HELLO. Далее идет цикл. В начале проверяется достигли ли мы конца строки. Конец строки это символ с кодом 0. Если это не конец строки, тогда надо вывести очередной символ. Вывод осуществляется с помощью прерывания BIOS — 0x10. В конце увеличиваем регистр bx на единицу.

Теперь нужно скомпилировать проект. Это делается в командной строке с помощью Nasm:

nasm -fbin boot_hello.asm -o boot_hello.bin

Запускаем полученный файл: boot_hello.bin в эмуляторе qemu

qemu-system-i386 boot_hello.bin

Ура! Получилось. Наше ядро здоровается со всем миром:

загрузчик ядра говорит привет

Как я продолжил разрабатывать загрузчик ядра.

Статья на канале Яндекс.Дзен