Обзор

Вступление

Ядро AchiOS написано на 16-битном языке ассемблера реального режима x86. Это обеспечивает легкий доступ к процедурам BIOS для работы с клавиатурой, экраном и дисководом для гибких дисков, поэтому нам не нужны сложные драйверы. Поэтому большая часть кода сосредоточена на реальных аспектах ОС: загрузке программ, системных вызовах и так далее.

Кроме того, AchiOS позволяет избежать сложностей сегментации в реальном режиме, существуя в одном сегменте 64 КБ. Первые 32 КБ (0–32767) ОЗУ зарезервированы для ядра; второй 32К для внешнего программного кода и памяти.

Состав

Это самые важные файлы и каталоги в zip-файле AchiOS:

  • source / - содержит весь исходный код ОС
  • source / bootload / - Источник для генерации BOOTLOAD.BIN, который добавляется в образ диска при сборке
  • source / features / - Компоненты AchiOS, такие как поддержка FAT12, строковые подпрограммы, интерпретатор BASIC и т. д.
  • source / kernel.asm - исходный файл ядра ядра, который извлекает другие исходные файлы
  • программы / - Исходный код программ, добавляемых в образ диска

Карта памяти

Это структура сегмента памяти 64 КБ после загрузки AchiOS:

0–24575 (шестнадцатеричный: 0h - 5FFFh)
Исполняемый код ядра 24K

24576–32767 (шестнадцатеричный: 6000h - 7FFFh)
Буфер операций с диском ядра 8K

32768–65535 (шестнадцатеричное: 8000h - FFFFh
32 КБ места для внешних программ

Итак, первые 32 КБ отведены коду ядра AchiOS и его буферу 8 КБ для выполнения дисковых операций. После этого у нас есть еще 32К памяти, на этот раз для внешних программ. Они загружаются на уровне 32 КБ и, следовательно, должны быть упорядочены до 32768, как описано в Руководстве разработчика приложений.

Путь кода

Когда компьютер запускается, он загружает загрузочный блок BOOTLOAD.BIN, который был вставлен в первый сектор (512 байт) образа гибкого диска сценарием сборки. Он загружает его в ячейку памяти 31744 (7C00h в шестнадцатеричном формате) и начинает его выполнение.

Затем BOOTLOAD.BIN сканирует дискету на наличие KERNEL.BIN и загружает его в ячейку памяти 2000h: 0000h. Здесь 2000h - это сегмент, а 0000h - смещение в этом сегменте - вам не нужно беспокоиться об этом, но на самом деле это означает, что ядро ​​загружается в ячейку 131072 (128 КБ) в ОЗУ ПК. (Вы получите полную ячейку памяти, умножив сегмент на 16 и добавив смещение.)

После того, как загрузчик загрузил ядро, он переходит в ячейку памяти 131072 (также известную как 2000h: 0000h), чтобы начать его выполнение. После этого для простоты мы игнорируем сегменты и просто используем смещения (от 0000h до FFFFh), тем самым предоставляя нам 64 КБ ОЗУ для использования.

В начале ядра у нас есть серия инструкций jmp. Почему они здесь? Что ж, системные вызовы находятся в полуслучайных местах исполняемого файла ядра. По мере развития AchiOS точное местоположение этих системных вызовов меняется; внешняя программа не может гарантировать их местонахождение. Итак, у нас есть список векторов в самом начале ядра, который jmp для этих вызовов, поэтому внешняя программа может вызывать эти векторы и знать, что они никогда не переместятся!

Непосредственно перед этими векторами есть jmp, чтобы пропустить их, а затем запускается основное выполнение ядра, настраивая различные вещи и предлагая пользователю выбор из списка программ или интерфейса командной строки.

Строительство

Требования к сборке: ассемблер NASM, пакет dosfstools, утилита mkisofs и root-доступ. Нам нужен root-доступ, потому что мы монтируем образ дискеты с обратной связью для вставки наших файлов.

Чтобы собрать AchiOS, откройте терминал и переключитесь на расширенный пакет AchiOS. Введите sudo bash в дистрибутивах со вкусом Ubuntu или просто su в других, чтобы переключиться на пользователя root. Затем введите:

./build-linux.sh

При этом будет использоваться NASM для сборки загрузчика, ядра и поставляемых программ, а затем загрузчик будет записан в образ дискеты achios.flp в каталоге disk_images /. (Он записывает 512-байтовый загрузчик в первый сектор образа гибкого диска, чтобы создать загрузочный сектор и настроить файловую систему, подобную DOS.) Затем сценарий сборки монтирует файл achios.flp образ в файловую систему - другими словами, монтирование образа, как если бы это была настоящая дискета. Сценарий копирует ядро ​​(kernel.bin) и двоичные файлы из каталога programs / перед отключением образа дискеты.

После этого сценарий запускает утилиту «mkisofs» для создания ISO-образа компакт-диска AchiOS, вставляя образ дискеты в качестве загрузочного раздела. Таким образом, мы получаем два файла в каталоге disk_images /: один для дискет и один для CD-R. Теперь вы можете использовать их в эмуляторе или на реальном ПК, как описано в разделе «Запуск» выше.

Изменение

Обзор

Самый простой способ протестировать код - создать новое приложение в каталоге programs /, собрать AchiOS и запустить вашу программу. Тогда вы можете быть уверены, что ваш код не мешает коду ядра (по крайней мере, на этапе сборки!). Когда он вас устраивает, вы можете добавить его в source / kernel.asm или в отдельный файл в source / features /.

Обратите внимание, что файлы в source / features / соответствуют системным вызовам в программах / achidev.inc (и подробно описаны в Руководстве разработчика приложений), но эти исходные файлы также включают внутренние вызовы, которые используются ядром и недоступны для пользовательских программ. Поэтому используйте grep или любой другой инструмент поиска, чтобы найти определенные вызовы, если они недоступны через API.

Системные вызовы

Добавлять новые системные вызовы легко и весело - они расширяют возможности AchiOS! Так что, если вы хотите помочь, это лучший способ начать. Откройте source / features / screen.asm в текстовом редакторе и вставьте следующее после текста заголовка:

Все системные вызовы должны начинаться с pusha и заканчиваться на popa перед ret: это сохраняет регистры в стеке в начале, а затем выталкивает их. в конце, чтобы мы не изменили кучу регистров и не запутали вызывающую программу. (Если вы передаете значение, скажем, в AX, вы должны сохранить AX во временном слове и поместить его обратно между popa и ret, как показано на os_wait_for_key в keyboard.asm.)

Тело нашего кода просто помещает местоположение нашей строки сообщения в регистр SI, а затем вызывает другую процедуру AchiOS, os_print_string. Вы можете свободно вызывать другие подпрограммы из своего системного вызова.

Как только мы это сделаем, мы сможем получить доступ к этой процедуре во всем ядре. А как насчет внешних программ? Они понятия не имеют, где в ядре находится этот вызов! Мы используем векторы - набор инструкций jmp в начале кода ядра, которые переходят к этим подпрограммам. Поскольку эти векторы находятся в начале, они никогда не меняют своего положения, поэтому мы всегда знаем, где они находятся.

Например, прямо сейчас ваш новый системный вызов может быть в ядре по адресу 0x9B9D. Но если вы добавите еще один вызов перед ним или кто-то другой сделает это, он может переместиться на 0x9FA6 в двоичном файле ядра. Мы просто не знаем, где это будет. Но если мы поместим вектор в начало нашего ядра, прежде чем что-либо произойдет, мы сможем использовать его в качестве отправной точки, поскольку вектор никогда не будет двигаться!

Откройте source / kernel.asm и прокрутите вниз до списка векторов системных вызовов. Вы можете видеть, что они начинаются с 0003h. Прокрутите список вниз, и вы увидите что-то вроде этого:

Давайте добавим вектор к нашему новому вызову. Добавьте это под существующими векторами:

Как мы узнаем, что этот jmp находится по адресу 00D2h в двоичном файле ядра? Что ж, просто следуйте шаблону в jmp выше - догадаться довольно легко. Если вы не уверены, вы всегда можете использовать ndisasm для дизассемблирования ядра и поиска последнего jmp в списке.

Это все хорошо, но есть еще один момент: люди, пишущие внешние программы, не хотят звонить по уродливому номеру, например 00C9h, когда они выполняют нашу рутину. Они хотят получить к нему доступ по имени, поэтому нам нужно добавить строку в achidev.inc в каталоге programs /:

Теперь любая программа, которая включает achidev.inc, сможет вызывать нашу подпрограмму по имени. Et voila: новый системный вызов для AchiOS!

Патчи

Если вы внесли некоторые улучшения или дополнения в AchiOS и хотите отправить их, отлично! Если это небольшие изменения - например, исправление ошибки или небольшая настройка - вы можете вставить измененный код в электронное письмо. Объясните, что он делает и где находится в исходном коде, и если все в порядке, мы его включим.

Если ваше изменение более масштабное (например, системный вызов) и затрагивает различные части кода, вам лучше установить патч. В UNIX-подобных системах, таких как Linux, вы можете использовать утилиту командной строки diff для создания списка ваших изменений. Для этого вам понадобится исходное (релизное) дерево исходного кода AchiOS, а также дерево вашего измененного кода. Например, у вас может быть исходный код в каталоге под названием achios-4.2 /, а ваша расширенная версия - в new-achios-4.0 /.

Перейдите в каталог под ними и введите:

diff -ru achios-4.2 new-achios-4.2 > patch.txt

Это сопоставляет различия между двумя каталогами и направляет вывод в файл patch.txt. Проверьте файл, чтобы убедиться, что он в порядке (вы можете увидеть, как он показывает, какие строки были изменены), а затем прикрепите файл к электронному письму.