Вторинний завантажувач Операційної Системи, dev64
Programming
Вторинний завантажувач операційної системи
Зміст
Відповідь. Boot Loader за розмірами всього 512 байт. У 512 байт можна вмістити перехід у захищений режим. У захищеному режимі перестають бути доступними функції BIOS до роботи з устаткуванням. Перейти в Boot Loader-e у захищений режим та завантажити ядро з диска не вдасться. Тому для завантаження великих ядер застосовується додатковий проміжний завантажувач, який працює у захищеному режимі. Boot Loader завантажує не ядро, а проміжний завантажувач. Проміжний завантажувач переходить у захищений режим, завантажує з файлової системи потрібне ядро і передає на нього керування. Оскільки проміжний завантажувач не обмежений у розмірах 512 байтами, він може бути набагато функціональнішим. Ядро операційної системи в цьому випадку може бути не простим binary файлом, а elf-файлом, що переміщається. При цьому проміжний завантажувач може бути досить складною програмою з великою кількістю можливостей. У тому числі може підтримуватися ряд типів завантажувальних пристроїв і файлових систем. І навіть може бути додано підтримку графічного режиму для краси. Крім того, проміжний завантажувач може надавати засоби для конфігурування ядра, або конфігурування режиму завантаження операційної системи.
Подібна схема із проміжним завантажувачем реалізується завантажувачем GNU GRUB. GNU GRUB використовується в GNU Linux, FreeBSD, NetBSD. Windows також використовує багатостадійну стадійну систему завантаження. Див ntldr.
У той же час існують операційні системи з невеликим ядром, яким не потрібно двостадійне завантаження. 512 байтним Boot Loader обходиться, наприклад QNX4 і Menuet OS. Зважаючи на все, цим і пояснюється обмеження на розмір ядра QNX4.
KolibriOS має багато різних варіантів завантажувача, у тому числі mtldr, що дозволяє конфігурувати завантаження KolibriOS усередині конфігураційних файлів Windows ntldr.
Де зберігається проміжний завантажувач? У GRUB для цього використовується термін "bootloader area". Пошук за цим терміном корисної інформації не дав. Щоб знайти відповідь на це запитання, потрібно копати документацію та вихідники GRUB.
Ще один варіант для завантаження великого ядра полягає у застосуванні упаковки. Ядро реалізується у вигляді коду, що саморозпаковується. Не обов'язково воно розпаковується цілком. Може розпаковуватись частина. Я застосовував упаковку для подолання проблеми розміру ядра QNX4. У QNX4 ядро містить віртуальну файлову систему, що є кореневою всім інших систем. У цю віртуальну систему можна помістити звичайні програми, що здійснюються, які будуть стартовані при завантаженні ядра. Ядро в тому числі містить у собі найпростіший shell, що дозволяє виконувати найпростіші скрипти. Це дозволяє додати додаткові драйвера в ядро і т.д. У моєму випадку, я реалізовував завантаження QNX4 з CD для подальшого накачування бекапа даних з ftp. Для цього додавав до ядра драйвер CD-приводу, мережні драйвера, інші утиліти. Але оскільки місця мені на всі утиліти не вистачало, довелося все це пакувати в один великий архів і розпаковувати своїм розпакувальником, також записаним у ядро. Розпакувальник використовував бібліотеку gzip для розпакування вкомпільованих у нього у вигляді звичайної константи даних архіву.
GRUB
Основна ідея GRUB, що просувається, — реалізація універсального завантажувача для безлічі операційних систем, що підтримує MultiBoot Specification:
Multiboot Specification
описує 3 угоди:
1. Формат ядра ОС. Це a.outабо ще краще формат elf. У перших 8 кілобайтах ядра повинна розміщуватися спеціальна структура, що описує ряд прапорів. Ця структура таки фігурувала у прикладі вище. Детальніше інформацію про структуру дивитись у прикладі
2. Multiboot Specification визначає стан процесора у момент, коли на ядро передається керування. Захищений режим вже включений, сегментні регістри завантажені селектори потрібних сегментів. У регістрі BX передається вказівник на структуру, що описує параметри, що передаються із завантажувача GRUB ядру. (Наприклад, параметри диска, з якого відбувається завантаження). Докладніше про стан у стандарті.
3. Multiboot Specification описує структуру, яка передається завантаженому в пам'ять ядру як параметр. Ядро має обробляти цю інформацію. Але якщо розробники хочуть, вони можуть її використати. Адреса за яким зберігається ця структура не перетинається з кодом та даними ядра. Більше нічого не гарантується. Ядро має само подбати про запобігання цим даних, якщо необхідно. Подробиці у тій же специфікації.
Підіб'ю підсумки. GRUB дозволяє створювати ядро у вигляді звичайного файлу elf. Єдина відмінність від простого здійснюваного файлу, ядро повинне починатися з асемблерної вставки, що описує спеціальну структуру з прапорами і так далі. Ця вставка ніяк не порушує структуру elf-файлу.
Мені поки не потрібно величезних ядер операційної системи, так само як і не потрібно переваг ядра в elf-овому форматі. Тому для експериментів використовую Boot Loader Menuet OS.
Boot Loader від Menuet OS
Це проста альтернатива GRUB. Він одностадійний. Завантажує ядро з файлу із зазначеним ім'ям із дискети відформатованої у форматі MSDOS (FAT12). Вихідники цього Boot Loader-a можна взяти зінсталяції Menuet OS. Крім того, доступна версія, що дозволяє перед завантаженням запитувати ім'я файлу ядра: http://www.menuetos.org/M32.htm
Скомпілювати Boot Loader його можна або за допомогою fasm або наsm. Далі його слід скопіювати на дискету. Для експериментів (швидше за все у мене не з першого разу вийде все як треба, потрібно написати собі програму, яка записуватиме 512 байтів у перший сектор дискети).
Утиліта для копіювання Boot Loader-a
Як вже говорилося вище, замість реальних дискет я використовую віртуальні дискети у вигляді звичайних дискових файлів. Утиліта для копіювання Boot Loader-a елементарно повинна взяти вміст скомпілованого 512 файлу, з Boot Loader-ом і записати його в перші 512 байтів файлу, що є image віртуальної дискети. Image віртуальної дискети у форматі MSDOS я отримав, набравши “MSDOS image” у Google. У результаті одержав посилання з дисковим image-м. http://www.allbootdisks.com/download/dos.html
Програма вийшла елементарною. Вихідники нижче. Я вирішив використати “голий С”. Для тренування перед написанням ядра. Не впевнений, що C + + хороший для ядра.
Як я і описував вище, програма копіює 512 байт з файлу, вказаного в першому параметрі файл, вказаний у 2-му параметрі. Дехто, швидше за все, захоче мене покритикувати побачивши goto, застосованих у коді. На критику відповідаю питанням: “А як зробити красивішим обробку помилок із закриттям файлових дескрипторів? Щоб при цьому ще не було повторень коду”.
Крім того, я в цьому коді вирішив відмовитися також від важкого printf() на користь “легкого” write().
CodeBlocks + MiniGW
Як IDE для написання я використав середовище CodeBlocks під Windows. http://www.codeblocks.org/downloads/
До цього середовища входить компілятор MiniGW. Я встановив саме версію із включеним у CodeBlocks MiniGW. І що тішить. Моя програма скомпілювалася і на FreeBSD і під Windows. Більше того, все працює як треба. Тож рекомендую CodeBlocks + MiniGW. І ще один дуже цікавий факт. CodeBlocks дозволяє дуже зручно перемикатися на описи змінних, инклудники і так далі. Це само по собі не здивує користувачів Visual Studio. Цікаво інше.
Так як я спочатку планував компілюватись під FreeBSD, я скопіював собі на машину /usr/include каталог з FreeBSD і вказав його у своєму CodeBlocks проекті. Додаткові инклудники підключилися і при перемиканні на який-небудь з .h-файлів CodeBlocks став пропонувати мені варіант куди переключитися - в инклудник від FreeBSD або инклудник з таким же ім'ям із встановленої з CodeBlocks інталяції MiniGW.
Мене дратувало наявність дублювання заголовників. Не знайшовши способу, як позбутися непотрібних мені іклудників MiniGW, я просто взяв і перемістив їх каталог в інше місце. А на їхнє місце поклав іклудники від FreeBSD. Яке ж моє здивування, що MiniGW з іклудниками від FreeBSD зумів скомпілюватися без проблем і зібрати працюючий exe-шник!
Тобто. по инклудникам MiniGW і gcc/gpp на FreeBSD цілком сумісні. Звичайно виконувати отримані файли будуть не завжди. Та й лінкуватимуться "тим більше" не завжди. Однак компіляцію таким чином можна перевірити безпосередньо під Windows. Факт сам собою дуже приємний. А простецькі програми можна навіть зібрати і працювати буде однаково. (Згодом з'ясувалося, що скомпільований під Windows exe-шник працював дивно. Замість 512 байт читав з деяких файлів менше. Можливо пов'язано з тим, що підWindows за промовчанням відкриваються “в текстовому режимі”. Тому є прапорець типу O_BINARY до функції open(). Але інклудники то я підмінив... Назад відновлювати не став. Довелося відмовитись від використання утиліти під Windows. Я маю віртуальну FreeBSD).