В принципе, можно использовать компилятор, который стоит в системе, но только тогда ему нужно будет передавать определённые флаги. Проще всего будет использовать кросс-компилятор, чтобы не заморачиваться со всем этим. Для наших нужд его можно либо скомпилировать вручную, либо взять готовый. В любом случае, есть хорошая инструкция на osdev wiki, как всё это настроить.
Чтобы тестировать ОС, потребуется эмулятор. Мы пишем ОС под i686, поэтому потребуется эмулятор для это платформы. Предлагается взять QEMU, потому что он умеет запускать ядро по ELF-файлу (без установки GRUB). Ссылка на официальный сайт. Проверьте, что у вас появился исполняемый файл qemu-system-i386
.
В этой папке лежит самое простое ядро, которое может загрузить QEMU. Всё, что оно делает — выводит на VGA-экран примитивный текст. Пока никаких прерываний, переключений контекста и ядерных штук :).
Этот файл содержит в себе описание специальной секции .multiboot
. Multiboot — это стандарт (или можно сказать протокол), который определяет порядок загрузки ядер из исполняемых файлов.
В самом начале файла располагается multiboot header, он состоит из трёх чисел:
magic
всегда равно0x1BADB002
flags
содержит битовую маску флагов, мы использует только первые два флага: ALIGN и MEMINFO. Первый говорит о включении выравнивания по границе страницы, а второй требует от загрузчика специальной информации о памяти.checksum
— просто контрольное число.
Загрузчик загружает ядро, в соответствии с тем, как указано в ELF-файле. А затем передаёт управление по адресу, который указан как entry point (в нашем случае _start).
Содержит простой код, который работает с VGA-фреймбуффером. По-сути, это двумерный массив, который описывает каждый пиксель. Когда в определённую ячейку что-то записывается, картинка на экране обновляется. Такая модель работы с периферией называется memory-mapped I/O или MMIO.
Вы программировали когда-нибудь линкер? Нет? Ну... Теперь самое время. Этот файл — linker script. Он описывает как располагаются секции внутри итогового исполняемого файла, а также какие у них выравнивания, флаги и по каким адресам они загружаются. Документация.
В QEMU есть дополнительные флаги, которые позволяют подключать GDB, чтобы наблюдать за работой ОС:
-s
запускает gdb-server на порту 1234 (если нужен другой, то смотрите опцию-gdb
)-S
запрещает QEMU начинать исполнение кода ядра до того момента, пока вы не подключитесь в gdb и не скажете продолжать
Чтобы подключиться из gdb:
(gdb) target remote localhost:1234
Или покороче:
(gdb) tar rem :1234
Дальше вам доступны основновные команды GDB. При отладке ISR'ов учтите, что они могут выполняться асинхронно. Поэтому чтобы в них гарантированно попасть, нужно поставить на них брейкпоинт.
- Напишите более умный терминал: как минимум, вам потребяется скроллинг :). Как максимум — более приятный API.
- Сделайте удобный printf — его сейчас нет, но как-то отлаживать нужно будет. Ещё понадобятся strlen, memset, memcpy.