[Из песочницы] Пишем операционную систему. Часть 1. Загрузчик
Всем привет! Сегодня мы напишем загрузчик, который будет выводить «Hello World» и запустим его на VirtualBox. Писать будем на ассемблере FASM. Скачать его можно отсюда. Также нам понадобится собственно VirtualBox и UltraISO. Перед тем как писать код, разберемся как загружаются операционные системы.
Итак, когда мы нажимаем большую кнопку включения на нашем компьютере запускается система, которая есть на любом компьютере — BIOS (Basic Input/Output System или базовая система ввода/вывода). Задача BIOS это:
- Обнаружить все подключенные устройства и проверить их на работоспособность. За это отвечает программа POST (Power On Self Test, самотестирование при включении). Если жизненно необходимое железо не обнаружено, то системный динамик (если таковой имеется) пропищит что-то непонятное и дальше загрузка не пойдет.
- Предоставить операционной системе функции для работы с железом.
- Считать самый первый сектор загрузочного устройства в нулевой сегмент оперативной памяти по смещению 0×7C00h и передать туда управление. 1 сектор на диске равен 512 байтам. Поэтому, наш загрузчик не должен превышать 512 байт. BIOS определяет, что сектор загрузочный по наличию в последних двух его байтах значений 0×55 и 0xAA.
Теперь можно приступать к написанию кода. Запускаем файл FASMW.EXE, который находится в архиве с FASM-мом и вставляем туда следующий код:
org 7C00h
start:
cli ;Запрещаем прерывания (чтобы ничего не отвлекало)
xor ax, ax ;Обнуляем регистр ax
mov ds, ax ;Настраиваем dataSegment на нулевой адрес
mov es, ax ;Настраиваем сегмент es на нулевой адрес
mov ss, ax ;Настраиваем StackSegment на нулевой адрес
mov sp, 07C00h ;Указываем на текущую вершину стека
sti ;Запрещаем прерывания
;Очищаем экран
mov ax, 3
int 10h
mov ah, 2h
mov dh, 0
mov dl, 0
xor bh, bh
int 10h
;Печатаем строку
mov ax, 1301h
mov bp, message
mov cx, 12
mov bl, 02h
int 10h
jmp $
message db 'Hello World!',0
times 510 - ($ - $$) db 0 ;Заполнение оставшихся байт нулями до 510-го байта
db 0x55, 0xAA ;Загрузочная сигнатура
Этот код требует немного пояснений. Командой
org 7C00h
мы говорим, что код нужно загружать в ОЗУ по адресу 0×7C00. В строках
mov ax, 3
int 10h
мы устанавливаем видео режим 80×25 (80 символов в строке и 25 строк) и тем самым очищаем экран.
mov ah, 2h
mov dh, 0
mov dl, 0
xor bh, bh
int 10h
Здесь мы устанавливаем курсор. За это отвечает функция 2h прерывания 10h. В регистр dh мы помещаем координату курсора по Y, а в регистр dl — по X.
mov ax, 1301h
mov bp, message
mov cx, 12
mov bl, 02h
int 10h
Печатаем строку. За это отвечает функция 13h прерывания 10h. В регистр bp мы помещаем саму строку, в регистр cx — число символов в строке, в регистр bl — атрибут, в нашем случае цвет, он будет зеленым. На цвет фона влияют первые 4 бита, на цвет текста — вторые 4 бита. Ниже представлена таблица цветов
0 - черный, 1 - синий, 2 - зеленый, 3 - желтый, 4 - красный, 5 - фиолетовый, 6 - коричневый, 7 - светло-серый, 8 - темно-серый, 9 - светло-синий, A - светло-зеленый, B - светло-желтый, C - светло-красный, D- светло-фиолетовый, E - светло-коричневый, F – Белый.
В строке
jmp $
Программа зависает.
Откомпилируем код нажатием клавиш Ctrl + F9 и сохраним полученный файл как boot.bin.
Запуск
Запускаем UltraISO и перетаскиваем наш бинарник в специальную область (отмечено красной стрелкой).
Далее кликаем правой кнопкой мыши по бинаринку и нажимаем кнопку примерно с такой надписью: «Установить загрузочным файлом». Далее сохраняем наш файл в формате ISO.
Открываем VIrtualBox и создаем новую виртуальную машину (если вы не знаете, как это делается, кликайте сюда). Итак, после того, как вы создали виртуальную машину, нажимаем «Настроить, выбираем пункт «Носители», нажимаем на «Пусто», там где «Привод» есть значок оптического диска. Нажимаем на него и выбираем «Выбрать образ оптического диска», ищем наш ISO файл, нажимаем «Открыть». Сохраняем все настройки и запускаем виртуальную машину. На экране появляется наш «Hello World!».
На этом первый выпуск подходит к концу. В следующей части мы научим наш загрузчик читать сектора диска и загрузим свое первое ядро!