З чого починається вивчення нової мови (або середовища) програмування? З написання простенькій програми, що виводить на екран коротке привітання типу "Hello World!". Наприклад, для C це буде виглядати приблизно так:
Показово, але зовсім нецікаво. Програма, звичайно, працює, вітання своє пише; але ж для цього потрібна ціла операційна система! А що якщо хочеться написати програмку, для якої нічого не треба? Вставляємо дискетку в комп'ютер, завантажується з неї і. "Hello World"! Можна навіть прокричати це вітання із захищеного режиму ...
Сказано зроблено. З чого б почати. Набратися знань, звичайно. Для цього дуже добре полазити в исходниках Linux і Thix. Перша система всім добре знайома, друга менш відома, але не менш корисна.
Підучилися? Тепер займемося. Зрозуміло, що в першу чергу треба написати завантажувальний сектор для нашої міні-операційки (а адже це буде саме міні-операційка!). Оскільки процесор вантажиться в 16-розрядному режимі, то для створення завантажувального сектора використовується асемблер і лінковщік з пакета bin86. Можна, звичайно, пошукати ще що-небудь, але обидва наших прикладу використовують саме його; і ми теж підемо по стопах вчителів. Синтаксис цього асемблера трохи дивакуватий, що суміщає риси, характерні і для Intel і для ATT, але після пари тижнів мук можна звикнути.
Завантажувальний сектор (boot.S)
Свідомо не буду приводити повних лістингів програм. Так стануть зрозуміліше основні ідеї, та й вам буде набагато приємніше, якщо все напишете своїми руками.
Для початку визначимося з основними константами.
START_HEAD = 0 - Головка приводу, що нею приємно використовувати.
START_TRACK = 0 - Доріжка, звідки почнемо читання.
START_SECTOR = 2 - Сектор, починаючи з якого будемо зчитувати наше ядерце.
SYSSIZE = 10 - Розмір ядра в секторах (кожен сектор містить 512 байт)
FLOPPY_ID = 0 - Ідентифікатор приводу. 0 - для першого, 1 - для другого
HEADS = 2 - Кількість головок приводу.
SECTORS = 18 - Кількість доріжок на дискеті. Для формату 1.44 МБ це кількість дорівнює 18.
Насамперед зробимо переміщення самих себе в більш прийнятне місце.
Тепер необхідно налаштувати як слід сегменти для даних (es, ds) і для стека. Неприємно, звичайно, що все доводиться робити вручну, але що поробиш - адже крім нас і BIOS в пам'яті комп'ютера нікого немає.
А повідомлення так
До цього часу на дисплеї комп'ютера з'явиться скромне "Booting data.". Це в принципі не гірше, ніж "Hello World", але давайте доб'ємося трохи більшого. Перейдемо в захищений режим і виведемо цей "Hello" вже з програми, написаної на C.
Ядро 32-розрядне. Воно буде у нас розміщуватися окремо від завантажувального сектора і збиратися вже за допомогою gcc і gas. Синтаксис асемблера gas відповідає вимогам ATT, так що тут все буде простіше. Але для початку нам потрібно прочитати ядро. Знову скористаємося готової функцією 0x2 переривання 0x13.
Сама функція читання гранично проста: довго і нудно заповнюємо параметри, а потім одним махом зчитуємо ядро. Складнощі почнуться, коли ядро перестане поміщатися в 17 секторах (тобто 8.5КБ); але це поки в майбутньому, а зараз цілком достатньо такого блискавичного читання
На даний момент на екрані виведено "Booting data. Done" і лампочка приводу флоппі-дисків погашена. Всі затихли і готові до смертельного номеру - стрибка в захищений режим.
Виведемо попередження - про те, що переходимо в захищений режим. Нехай всі знають, які ми важливі.
Поки у нас ще живий BIOS, запам'ятаємо позицію курсору і збережемо її у відомому місці (0000: 0x8000). Ядро пізніше забере всі дані і буде їх використовувати для виведення на екран переможного повідомлення.
Тепер увагу, забороняємо переривання (нема чого відволікатися під час такої роботи) і завантажуємо таблицю дескрипторів
У нас таблиця дескрипторів складається з трьох описателей: нульовий (завжди повинен бути присутнім), сегменту коду і сегменту даних.
Перехід в захищений режим може відбуватися мінімум двома способами, але обидві ОС, обрані нами для прикладу (Linux і Thix) використовують для сумісності з 286 процесором команду lmsw. Ми будемо діяти тим же способом
Ось і вся робота завантажувального сектора - чимало, але й не багато. Тепер з ним ми попрощаємося і попрямуємо до ядра.
В кінці ассемблерного файлу корисно додати наступну інструкцію.
В результаті скомпільований код буде займати рівно 512 байт, що дуже зручно для підготовки образу завантажувального диска.
Перші подихи ядра (head.S)
Ядро, на жаль, знову почнеться з ассемблерного коду. Але тепер його буде зовсім небагато.
Ми власне задамо правильні значення сегментів для даних (ES, DS, FS, GS). Записавши туди значення відповідного дескриптора даних.
Викличемо довгоочікувану функцію, вже написану на С.
І більше нам тут робити нічого.
Поговоримо на мові високого рівня (start.c)
Тепер, щоб не плутатися з вбудованими в glibc функціями, скасуємо їх визначення
І почнемо, нарешті, писати код на мові високого рівня. правда, з невеликими асемблерними вставками.
Ось і вивели ми цей "Hello World" на екран. Скільки зроблено роботи, а на екрані тільки два рядки
А що - погано. Закричала нова операційна система. Світ з радістю сприйняв її. Хто знає, може бути - це новий Linux.
Підготовка завантажувального образу (floppy.img)
Тепер підготуємо завантажувальний образ нашої сістемкі.Для початку зберемо завантажувальний сектор.
Обріжемо 32-бітний заголовок і отримаємо таким чином чистий двійкового коду.
І з'єднаємо воєдино завантажувальний сектор і ядро
Образ готовий. Записуємо на дискетку (підготуйте кілька для експериментів, я прикінчив три штуки), перезавантажуємо комп'ютер і насолоджуємося ...
Е-мое, що ж я зробив ...: - []
Здорово, правда? Приємно відчути себе майбутнім Торвальдс, або кимось ще. Перша стежка протоптана, можна сміливо йти вперед - дописувати й переписувати систему! ...
Описана процедура наразі єдина для безлічі операційних систем, будь то UNIX або Windows. Що напишете ви. не знає ніхто. Адже це буде вже ваша система ...