В преддверии Нового Года бороздил просторы сети, и нашёл замечательную демку на ассемблере рисования новогодней ёлки. Демка не простая, а золотая, написана таким образом, чтобы работала в загрузочном секторе диска, фактически микрооперационная система, если её так можно назвать. Из-за большой любви к Новому Году и ассемблеру, решил таки её немного разобрать, и восхититься мастерством автора. Итак, поехали.
Что за демка и где её искать?
Данную демку нашёл в этом гит репозитории: TreeOS: a 16-bit bootsector Christmas tree demo.
Как гласит название:
Добро пожаловать в TreeOS (древесную операционную систему)! Это очень простая, хакерская, но работающая демка, которая рисует крутящуюся
новогоднююрождественскую ёлку и выдаёт небольшое сообщение. При этом работает на голом аппаратном обеспечении персонального компьютера, без операционной системы, используя только стандартное VGA-оборудование. СНовым ГодомРождеством.
Забегая вперёд скажу, что там две версии: с надписью и без (как в картинке на заходнике). Демка — это образ загрузочный дискеты. Написана она 16-ти битным кодом, который использует BIOS для загрузки с диска и изменяет видеорежим перед работой непосредственно с буфером кадра VGA. В коде используется стандартный 256-цветный режим 320х200 (режим VGA 13h). По идее это должно работать на любом персональном компьютере, но тестировалось только на виртуальной машине (в qemu). Лично я протестировал, что она отлично работает и в VirtualBox. Ниже я расскажу, как её запустить.
Пробуем запустить
Ну как обычно, прежде чем посмотреть код, насладиться его работой, так сказать пошуршать мозгами, сразу запустим? Конечно же да!
Поехали!
Для старта нам понадобиться компилятор nasm, виртуальная машина qemu или VirtualBox, кому что милее. Лично я решил попробовать и там и там. Потому ставим всё вместе:
sudo apt install nasm qemu-system-x86
Клонируем репозиторий, переходим в него и пробуем собрать пример.
git clone https://github.com/cfallin/treeos
cd treeos/
make qemu
И… И счастье не настало, хотя было так близко.
nasm -fbin -o treeos.img treeos.asm
treeos.asm:15: error: attempt to define a local label before any non-local labels
treeos.asm:47: error: attempt to define a local label before any non-local labels
treeos.asm:52: error: attempt to define a local label before any non-local labels
treeos.asm:60: error: attempt to define a local label before any non-local labels
treeos.asm:65: error: attempt to define a local label before any non-local labels
Makefile:5: ошибка выполнения рецепта для цели «treeos.img»
make: *** [treeos.img] Ошибка 1
Пришлось расчехлить гугл, и вспомнить в чём же проблема. А проблема оказалась очень простая. Автор использовал метки с точкой, а компилятору это не нравилось. После того, как я поправил все метки, убрав из них точки, всё получилось.
Например:
...
jmp 0:.newseg
.newseg:
mov ax, 0
...
изменил на
...
jmp 0:newseg
newseg:
mov ax, 0
...
Компиляция тоже идёт достаточно интересно. Не буду приводить Makefile, его каждый может посмотреть самостоятельно. Более интересно как идёт создание образа флоппи диска:
make qemu
nasm -fbin -o treeos.img treeos.asm
rm -f floppy.img
dd if=/dev/zero of=floppy.img bs=1024 count=1440
1440+0 записей получено
1440+0 записей отправлено
1474560 байт (1,5 MB, 1,4 MiB) скопирован, 0,00373289 s, 395 MB/s
dd if=treeos.img of=floppy.img conv=notrunc
3+1 записей получено
3+1 записей отправлено
1998 байт (2,0 kB, 2,0 KiB) скопирован, 0,000193295 s, 10,3 MB/s
qemu-system-x86_64 -fda floppy.img
Как видно, идёт компиляция ассемблеровского файла.
Затем идёт удаление возможного старого образа флоппи диска.
Команда dd создаёт чистый образ дискетки, после чего в начало записывается готовый бинарник ёлочки.
Ну и последняя команда запускает виртуальную машину qemu с этим образом. В результате получим вот такую замечательную демку.
В реальности не так сильно тормозит, как гифка.
Что делать, если сижу под Windows, а посмотреть демку хочется?
Ну самый лучший вариант, это собрать всё на виртуалке, а затем записать на живую дискету и загрузиться. Но где сегодня найти флоппи дисковод и дискеты?
Поэтому рассказываю как посмотреть демку на VirtualBox. Я специально сохранил оба образа дискеты с надписью и без.
В витуалбоксе создаём новую машину, можно даже не подключать жёсткий диск, он нам не нужен. Но для работы нужно добавить флопи-контроллер, делается это следующим образом.
После чего, скармливаем ему готовый образ TreeOS и наслаждаемся новогодним настроением.
Ёлка на VirtualBox.
Если очень хочется в живую запустить?
Зазгрузка с флешки
Как я уже сказал, идеально записать образ на флопи-диск. Но если его нет, можно записать на флешку. Для начала стираем флешку, забивая её нулями.
dd if=/dev/zero of=/dev/sdx
После этого копируем образ TreeOS в начальный бутсектор диска.
dd if=/mountedlocation/treeosFloppy.img of=/dev/sdx bs=512 count=4
Затем, используя утилиту CFDISK c помощью командной строки, помечаем сектор MBR как загрузочный сектор тип 0c FAT32.
Это добавит таблицу разделов к пустому пространству в секторе 0. Содержимое TreeOS останется в нулевом секторе после данной операции. Всё, можно пробовать загрузиться с флешки и загрузка не должна сильно отличаться от загрузки с дискетки.
Загрузка с жёсткого диска
Есть два пути загрузки с жёсткого диска. Первый путь, это подготовить его точно так же, как мы делали флешку, но тогда все данные на жёстком диске будут уничтожены.
Есть альтернатива этому решению. Копируем файл treeosFloppy.img в корень NTFS раздела: c:treeos.mbr
.
После этого настраиваем Windows BOOTMGR и/или NTLDR чтобы TreeOS было помещено в загрузочное меню Windows вместе с самой Windows.
В результате при загрузке можно будет выбирать что загружать, Windows или эту микроОС.
Точно так же можно настроить и GRUB.
Пару слов об ассемблере
Буду честен, в х86 ассемблере слаб. Но всё же крупными штрихами постараюсь описать то что происходит. Гуру ассемблера могут справедливо меня поправить в комментариях. Прошу не бить сильно, и не пинать. Разберём свежую (последний коммит был пять дней назад) 512 байтовую версию.
Запрещаем прерывания и очищаем регистры. Инициализируем указатель стека. Разрешаем прерывания.
Очищаем экран, записывая «чёрные» пробелы на экран. Поясняю, что палитра может иметь цвет фона и текста.
Здесь идёт инициализация системного таймера.
Здесь мы переходим с помощью 13-прерывания BIOS в VGA-режим.. Код 0x13 соответствует разрешению 320x200 и 256 цветовой палитре.
После чего попадаем в глобальный цикл. Где мы получаем текущий «тик» системного таймера в регистр BX и очищаем буфер картинки для следующего фрейма.
А вот ниже творится настоящая магия. Так как я совершенно не знаю ассемблер математического сопроцессора, то детально рассказать что там происходит не могу. Но у нас есть формула выше, по которой расчитывается график ёлочки.
И ниже пошёл ассемблер работы с плавающей точкой. Там в памяти рассчитывается и формируется новый фрейм ёлки.
Обратите внимание на операцию сравнения регистра cx
c 1000
и если он равен, то мы переходим на метку treedone
. Глянем, что же на этой метке.
Итак, в clipped
мы инкрементируем регистр cx
и джампимся опять в цикл расчёта ёлки. В treedone
мы копируем буфер получившейся ёлки в реальный фреймбуффер видеокарты с помощью магической инструкции rep movsw
(чесслово только узнал о ней).
Тут не самое элегантное место, мы просто тупо крутимся в цикле, пока счётчик таймера у нас не изменится.
Это у нас обработчик прерывания системного таймера, относительно которого мы и синхронизируем вращение и отрисовку ёлочки.
В самом низу у нас находятся вспомогательные расчётные константы (я не стал все приводить сюда).
В версии от 2019 года, есть ещё дополнительная надпись. Она задана константно и выводится с помощью кода:
А сама надпись представляет собой просто изображение, скрытое в бинарных константах.
Не буду приводить всё, и так понятно.
Как по мне, это прекрасная демка выходного дня, чтобы поупражняться в ассемблере, вспомнить молодость и, так сказать, запилить новогоднее настроение!
С Наступающим Новым Годом!!!
Дорогие коллеги, от всей души хочу поздравить вас всех с наступающим Новым Годом! Пускай в Новом Году будет больше творческих свершений, позитивных эмоций, вдохновения, сил, а так же возможностей для самореализации!
Рождественская демка под ДОС 1986 г.
Автор: Сергей