§ Загрузка BIOS
Когда компьютер начинает работу, то он проходит множество этапов загрузки. Самым первым делом, устанавливается адрес F000:FFF0, в реальном режиме работы процессора (правда, я сейчас не знаю, как современные компьютеры загружаются), и вот оттуда начинает работать биос (или его аналог), который проверяет диски, память, все внутренние подсистемы, инициализирует все что может.И вот как раз именно после всех инициализации, условно будем называть это биосом (efi, uefi, bios, у него куча разных названий сейчас появилось), вызывает первый сектор (Master Boot Record, если не по-нашему) с какого-нибудь диска, даже с сети может, неважно, и укладывает этот сектор адресу в памяти 0000h : 7C00h. Понятное дело, что размер сектора равен 512 байтам. Попробуй развернись в этом количестве байт и сделай что-то! Нет, находятся умельцы, которые и кубы крутят, и шахматы мутят.
§ Что делать дальше
Чем заняться после загрузки в память? Конечно, надо что-то инициализировать, как же без инициализации, все инициализируют, а я что, хуже что ли? Я тоже буду.1org 7C00h ; Указываем ассемблеру, что код начинается с 7C00h 2cli ; IF=0 теперь прерывания не вызываются 3cld ; DF=0 теперь все lods/movs/stos/etc возрастают 4xor ax, ax ; AX=0000 5mov ds, ax ; DS=0000 6mov es, ax ; ES=0000 7mov ss, ax ; SS=0000 8mov sp, 7C00h ; SP=7C00 9; ... остальной код ... 10times (7C00h-$)+510 db 255 ; Заполнить FFh оставшиеся 510 байт 11dw 0xAA55 ; Сигнатура бутсектораЗамечу, что если у бутсектора не будет в конце сектора 2 байта с сигнатурой
55 AA
, то такой бутсектор будет считаться биосом не бутсектором, а мусором и ничего он не загрузит.А где же
CS=0000
? Он и так ноль, так что все в порядке. После инициализации, конечно, интересно узнать, а как же этот бутсектор записать, чтобы он вообще как-нибудь заработал? И вот тут начинаются проблемы вселенского масштаба.Как и обычно, надо ассемблер включить. Он всегда находится под рукой и называется flat assembler. Очень удобный.
После сложных установок, настроек, калибровки, интеграции и инкапсуляции в хост-систему, можно будет написать приблизительно такой запускной файл, например, makefile:
1fasm boot.asm boot.binС помощью этого набора команд будет сформирован новый файл
boot.bin
, в котором и будет содержаться бутсектор.§ Отладчик bochs
Про этот отладчик я узнал очень давно, еще когда сидел наwindows xp
, а не в линуксе, как сейчас, и потому пользоваться я им, конечно, не научился толком, но кое-что загружать получалось. Как настроить отладчик, я уже сто раз писал везде где ни попадя. Настраиваю я его под winxp, конечно же. А как же линукс? Какой еще линукс? Нет никакого линукса, есть винда и она навсегда.Проблема следующая. Файловую систему разметить с помощью винды мне не удастся, потому придется изобретать свои велосипеды на языке программирования
php
, чем далее я и буду заниматься после того, как бутсектор напишу.Для того, чтобы загрузить сектор, надо диск создать. Утилита bximage в этом мне поможет хотя бы:
- Тип диска — hd
- Способ записи — flat
- Количество мегабайт — 256 (сойдёт для сельской местности)
- Имя диска — c.img
1ata0-master: type=disk, path="c.img", mode=flatПоэтому эту строку можно добавить в файл конфигурации c.bxrc.
1megs: 32 2romimage: file=c:/bochs/BIOS-bochs-latest 3vgaromimage: file=c:/bochs/VGABIOS-lgpl-latest 4ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 5ata0-master: type=disk, path="c.img", mode=flat, biosdetect=auto, translation=auto 6boot: c 7display_library: win32, options="gui_debug" 8log: bochsout.txt 9mouse: type=ps2, enabled=0, toggle=ctrl+mbutton 10cpu: ips=15000000 11clock: sync=both 12keyboard: keymap=c:/bochs/keymaps/x11-pc-us.map 13magic_break: enabled=1Тут есть зависимая конфигурация keymap, если она находится в другом месте, надо поправить путь. Тут есть такая опция как
magic_break
, если она активирована, то отладчик будет останавливаться на инструкции xchg bx,bx
что просто крайне полезно, потому что без этого отладка почти что невозможна.Запускать этот файл надо так (предварительно в makefile какой-нибудь оформить или bat-файл):
1bochsdbg -f c.bxrc -qЯ сейчас проверил, у меня все заработало. Конечно, чтобы это все заработало, надо, чтобы все было правильно настроено. Без точной настройки ничего работать не будет.
§ Как запустить загрузчик
Есть несколько идей, как это сделать. Первая — велосипедом, вторая... не знаю. Придется велосипедом. Создам файлmain.cc
, например:1#include <stdlib.h> 2#include <stdio.h> 3 4int main(int argc, char* argv[]) { 5 return 0; 6}Компилировать известно как:
g++ main.cc -o bootwriter
. Должно заработать. Makefile будет выглядеть примерно так:1NAME=bootwriter.exe 2all: $(NAME) 3 fasm boot.asm boot.bin 4$(NAME): main.cc 5 g++ main.cc -o $(NAME) 6 strip $(NAME)То есть, если нет файла bootwriter.exe, то он его создает. На линуксе это может и не будет работать, не проверял — страшно.
Вопрос такой — как нарисовать сову? Делается очень легко! Сначала сделайте два кружочка. Если два кружочка готовы, нарисуйте сову целиком. Сова готова! Следующий код для
main.cc
будет это правило демонстрировать:1unsigned char buf[512] = {0}; 2 3if (argc < 3) return -1; // Аргументов должно быть 2 4 5// Открыть файл на чтение и второй файл на запись 6FILE* fr = fopen(argv[1], "rb"); 7FILE* fw = fopen(argv[2], "rb+"); 8 9// Если один из них открыть не удалось 10if (fr == NULL || fw == NULL) return -2; 11 12// Прочесть и записать 446 байт (не 512!) 13fread(buf, 1, 446, fr); 14fwrite(buf, 1, 446, fw); 15 16// Подготовить 55 AA и записать в последние 2 байта первого сектора 17buf[0] = 0x55; buf[1] = 0xAA; 18 19fseek(fw, 510, SEEK_SET); 20fwrite(buf, 1, 2, fw); 21 22// Закрыть файлы 23fclose(fr); 24fclose(fw);Что делает этот код?
1$(NAME) boot.bin c.img
Если его запустить так, то код перепишет первые 446 байт в первый сектор и запишет сигнатуру, чтобы биос распознал этот сектор. Вот теперь можно уже попробовать написать что-нибудь, например, Hello World, в самом main.asm:1 mov si, Hello ; Ссылка на строку Hello 2@@: lodsb ; Загрузка нового символа в AL 3 and al, al ; Проверить AL на 0 4 je $ ; Если 0, то остановить процессор 5 mov ah, 0Eh ; AH=0Eh код печати символа 6 int 10h ; Печать символа 7 jmp @b ; Повтор 8Hello: db "Hello World",0Осталось только скомпилировать и запустить. У меня все нормально получилось.
Самое главное в программировании, это конечно, написать "HELLO WORLD". Если этого не будет, то зачем тогда программировать?
Файл как обычно, можно скачать: 01-hello-world.zip