Как создать операционную систему самому. Как написать операционную систему с нуля. Входная точка на ассемблере

Сразу говорю, не закрывайте статью с мыслями «Блин, еще один Попов». У него всего-то слизанная Ubuntu, а у меня все с нуля, включая ядро и приложения. Итак, продолжение под катом.

Группа ОС: вот .
Сначала я кину вам один скриншот.

Больше их нет, а теперь поподробнее о том, зачем я ее пишу.

Был теплый апрельский вечер, четверг. Я еще с детства мечтал написать ОС, как вдруг подумал: «Я же теперь знаю плюсы и асм, чего бы не воплотить мою мечту?». Загуглил сайты по этой тематике и нашел статью с Хабра: "Как начать и не бросить писать ОС ". Спасибо ее автору за ссылку на OSDev Wiki внизу. Я зашел туда и начал работу. Там были в одной статье все данные о минимальной ОС. Я начал собирать кросс-gcc и binutils, а потом все переписал оттуда. Видели вы бы мою радость, когда я увидел надпись «Hello, kernel World!» Я прямо со стула подпрыгнул и понял - я не сдамся. Я написал «консоль» (в кавычках, у меня не было доступа к клавиатуре), но потом решил написать оконную систему. В итоге она заработала, но доступа к клавиатуре у меня не было. А потом я решил придумать название, опираясь на X Window System. Загуглил Y Window System - она есть. В итоге назвал Z Window System 0.1, входящая в OS365 pre-alpha 0.1. И да, ее не видел никто, кроме меня самого. Потом я понял, как реализовать поддержку клавиатуры. Скрин самой первой версии, когда еще не было ничего, даже оконной системы:

В ней даже не двигался курсор текста, как вы видите. Затем я написал парочку простых приложений на основе Z. И вот релиз 1.0.0 alpha. Там были много вещей, даже меню системы. А файловый менеджер и калькулятор просто не работали.

Меня прямо терроризировал друг, которому важны одни красивости (Митрофан, сорри). Говорил «Запили VBE-режим 1024*768*32, запили, запили! Ну запили!». Ну я уже устал его выслушивать и все-таки запилил его. О реализации ниже.

Я сделал все моим загрузчиком, а именно GRUB"ом. С его помощью можно задать графический режим без осложнений путем добавления нескольких магических строчек в заголовок Multiboot.

Set ALIGN, 1<<0 .set MEMINFO, 1<<1 .set GRAPH, 1<<2 .set FLAGS, ALIGN | MEMINFO | GRAPH .set MAGIC, 0x1BADB002 .set CHECKSUM, -(MAGIC + FLAGS) .align 4 .long MAGIC .long FLAGS .long CHECKSUM .long 0, 0, 0, 0, 0 .long 0 # 0 = set graphics mode .long 1024, 768, 32 # Width, height, depth
А потом из структуры информации Multiboot я беру адрес фреймбуфера и разрешение экрана и пишу туда пиксели. VESA все сделали очень замороченно - цвета RGB надо вводить в обратном порядке (не R G B, а B G R). Я несколько дней не понимал - почему пиксели не выводятся!? В итоге я понял, что забыл поменять значения 16 цветовых констант с 0...15 на их RGB-эквиваленты. В итоге релизнул, заодно запилил градиентный фон. Потом я сделал консоль, 2 приложения и релизнул 1.2. Ах да, чуть не забыл - скачать ОС можно на

Автор Vulf gamer задал вопрос в разделе Другие языки и технологии

Как создать свою ОС? и получил лучший ответ

Ответ от Александр Багров[гуру]
Идея похвальная.
Прежде всего нужно знать систему команд машины, для которой намереваешься писать ОС.
Система команд находит свое прямое отражение в языке ассемблера.
Поэтому в первую очередь нужно придумать свой язык ассемблера и написать для него программу (ассемблер) , транслирующий буквенно-цифровую символику в машинный
код.
Если интересно, то можно посмотреть, какими бы требования должна обладать новая (идеальная) ОС.
Некоторые такие черты перечислены тут:
.ru/D_OS/OS-PolyM.html#IdealOS
Необходимо изучать материалы сайтов-разработчиков микропроцессоров. Например, Intel и AMD.
Возможно, тебе будет полезен видео-курс лекций по ОС, который представлен здесь:
.ru/D_OS/OS_General.html
PS: Не слушай пессимистов. Исходи из идеологии петуха, гонящегося за курицей:
"Не догоню, хоть разогреюсь. "
Источник: Сайт "Используй ПК правильно! "

Ответ от 2 ответа [гуру]

Привет! Вот подборка тем с ответами на Ваш вопрос: Как создать свою ОС?

Ответ от Вадим Хпрламов [новичек]
Конечно) Тут-же одни гейтсы сидят) На майкрософте спроси)



Ответ от Ирина стародубцева [новичек]
возьми все ОС и в одну запихай


Ответ от Александр Тунцов [гуру]
Ознакомься с ОС Linux, обучись программированию и в путь


Ответ от ~In Flames~ [гуру]
Программирование учить на высшем уровне, собрать целую толпу таких же компьютерных гениев и тогда уже можно делать.


Ответ от Rasul Magomedov [гуру]
Начни с создания нескучных обоев


Ответ от Капитан Гугл [гуру]
Про "10 лет на изучение основ" - не слушай, Торвальдс первую версию Линукса написал в 22 года, а компьютер у него в 12 появился. Как ты понимаешь, он не только основы изучал.
Начни с изучения уже существующего - с одной стороны, "Современные операционные системы" Танненбаума, с другой стороны - собери Linux From Scratch, с третьей - учи Ассемблер, C, C++. За все про все - можно в 3-4 года уложиться. После этого можешь приступать к разработке своей системы... если еще захочешь.


Ответ от Ёаня Семенов [гуру]
знаешь как делал Гейтс? попробуй так же, говорят прибыльно получается..
когда его наказали родители, он от нечего делать стал прыгать попой на клаве, потом продал назвав то что получилось " windows "
п с а если реально то напиши сначала "Hello World" в С++ и сразу поймешь что идея параноидальная


Ответ от Kostafey [гуру]
А зачем? Чем принципиально не устраивают существующие? Неужели нет ни одной, хоть частично удовлетворяющей вашим требованиям к ОС? Может стоит лучше присоединиться к команде разработчиков? Толку в 100500 раз больше будет.
И потом, вы забросите эту идею еще на 0,(0)1% ее реализации.


Ответ от Евгений Ломега [гуру]
Э. Таненбаум "Операционные системы: разработка и реализация "
удачи
PS К сожалению как это делал Бил Гейтс у тебя вряд ли получится. У него мама крутая банкирша, у тебя?


Ответ от Krab Bark [гуру]
Написать простейшую ОС самому можно, но она никак не сможет конкурировать с ОС вроде Windows, MAC OS или Linux, над которыми минимум десяток лет трудились сотни или тысячи программистов. Кроме того, ОС - только фундамент. Нужно, чтобы разработчики оборудования писали для этой ОС свои драйверы, разработчики прикладных программ писали для нее редакторы, плееры, браузеры, игры, черта в ступе... А без этого ОС останется никому не нужным фундаментом для дома, который никто строить не будет.


Ответ от Вадим Стаханов [активный]
Лучше бы на филолога пошел бы учится. А потом бы кричал "Свободная касса! "


Ответ от =Serge= [гуру]
Ура! Наконец то 58 вопрос на сайте про создание "своей" ОС))
Вот вопросы про "написать свою ОС" - их только 34))
Читай....92 вопроса*10 ответов = приблизительно 920 ответов))
Заодно возможно поймешь что значат "нескучные обои")).


Ответ от Irreproducible [гуру]
еще один Денис Попов с очередным BolgenOS"ом?


Ответ от Иван татарчук [новичек]
запусти блокнот скачай компилятор жабаскрипт и начни прыгать попой по клавиатуре
через 60мин компилируй и все
твоя оска готова


Ответ от Овечка Мила [новичек]
ОС? Какая именно? ОС-орижинал честер (оригинальный персонаж (в переводе))
Она нужна доя изображения себя мультиках или фильмах.
1. Придумай какого именно мультика/фильма ты хочешь ОС
2. Рассмотрим стиль мультика/фильма
3. Кем будет твой персонаж (фея, пони, маг, робот и т. п.)
4. Опиши мысленно его, потом на бумаге
5. Придумай дизайн
6. Придумай имя и био
7. Нарисуй персонажа!
8. Теперь за дело с Пэинт Туд Саи

Руководство по созданию ядра для x86-системы. Часть 1. Просто ядро

Давайте напишем простое ядро, которое можно загрузить при помощи бутлоадера GRUB x86-системы. Это ядро будет отображать сообщение на экране и ждать.

Как загружается x86-система?

Прежде чем мы начнём писать ядро, давайте разберёмся, как система загружается и передаёт управление ядру.

В большей части регистров процессора при запуске уже находятся определённые значения. Регистр, указывающий на адрес инструкций (Instruction Pointer, EIP), хранит в себе адрес памяти, по которому лежит исполняемая процессором инструкция. EIP по умолчанию равен 0xFFFFFFF0 . Таким образом, x86-процессоры на аппаратном уровне начинают работу с адреса 0xFFFFFFF0. На самом деле это - последние 16 байт 32-битного адресного пространства. Этот адрес называется вектором перезагрузки (reset vector).

Теперь карта памяти чипсета гарантирует, что 0xFFFFFFF0 принадлежит определённой части BIOS, не RAM. В это время BIOS копирует себя в RAM для более быстрого доступа. Адрес 0xFFFFFFF0 будет содержать лишь инструкцию перехода на адрес в памяти, где хранится копия BIOS.

Так начинается исполнение кода BIOS. Сперва BIOS ищет устройство, с которого можно загрузиться, в предустановленном порядке. Ищется магическое число, определяющее, является ли устройство загрузочным (511-ый и 512-ый байты первого сектора должны равняться 0xAA55 ).

Когда BIOS находит загрузочное устройство, она копирует содержимое первого сектора устройства в RAM, начиная с физического адреса 0x7c00 ; затем переходит на адрес и исполняет загруженный код. Этот код называется бутлоадером .

Бутлоадер загружает ядро по физическому адресу 0x100000 . Этот адрес используется как стартовый во всех больших ядрах на x86-системах.

Все x86-процессоры начинают работу в простом 16-битном режиме, называющимся реальным режимом . Бутлоадер GRUB переключает режим в 32-битный защищённый режим , устанавливая нижний бит регистра CR0 в 1 . Таким образом, ядро загружается в 32-битном защищённом режиме.

Заметьте, что в случае с ядром Linux GRUB видит протоколы загрузки Linux и загружает ядро в реальном режиме. Ядро самостоятельно переключается в защищённый режим.

Что нам нужно?

  • x86-компьютер;
  • Linux;
  • ld (GNU Linker);

Задаём точку входа на ассемблере

Как бы не хотелось ограничиться одним Си, что-то придётся писать на ассемблере. Мы напишем на нём небольшой файл, который будет служить исходной точкой для нашего ядра. Всё, что он будет делать - вызывать внешнюю функцию, написанную на Си, и останавливать поток программы.

Как же нам сделать так, чтобы этот код обязательно был именно исходной точкой?

Мы будем использовать скрипт-линковщик, который соединяет объектные файлы для создания конечного исполняемого файла. В этом скрипте мы явно укажем, что хотим загрузить данные по адресу 0x100000.

Вот код на ассемблере:

;;kernel.asm bits 32 ;nasm directive - 32 bit section .text global start extern kmain ;kmain is defined in the c file start: cli ;block interrupts mov esp, stack_space ;set stack pointer call kmain hlt ;halt the CPU section .bss resb 8192 ;8KB for stack stack_space:

Первая инструкция, bits 32 , не является x86-ассемблерной инструкцией. Это директива ассемблеру NASM, задающая генерацию кода для процессора, работающего в 32-битном режиме. В нашем случае это не обязательно, но вообще полезно.

Со второй строки начинается секция с кодом.

global - это ещё одна директива NASM, делающая символы исходного кода глобальными. Таким образом, линковщик знает, где находится символ start - наша точка входа.

kmain - это функция, которая будет определена в файле kernel.c . extern значит, что функция объявлена где-то в другом месте.

Затем идёт функция start , вызывающая функцию kmain и останавливающая процессор инструкцией hlt . Именно поэтому мы заранее отключаем прерывания инструкцией cli .

В идеале нам нужно выделить немного памяти и указать на неё указателем стека (esp). Однако, похоже, что GRUB уже сделал это за нас. Тем не менее, вы всё равно выделим немного места в секции BSS и переместим на её начало указатель стека. Мы используем инструкцию resb , которая резервирует указанное число байт. Сразу перед вызовом kmain указатель стека (esp) устанавливается на нужное место инструкцией mov .

Ядро на Си

В kernel.asm мы совершили вызов функции kmain() . Таким образом, наш “сишный” код должен начать исполнение с kmain() :

/* * kernel.c */ void kmain(void) { const char *str = "my first kernel"; char *vidptr = (char*)0xb8000; //video mem begins here. unsigned int i = 0; unsigned int j = 0; /* this loops clears the screen * there are 25 lines each of 80 columns; each element takes 2 bytes */ while(j < 80 * 25 * 2) { /* blank character */ vidptr[j] = " "; /* attribute-byte - light grey on black screen */ vidptr = 0x07; j = j + 2; } j = 0; /* this loop writes the string to video memory */ while(str[j] != "\0") { /* the character"s ascii */ vidptr[i] = str[j]; /* attribute-byte: give character black bg and light grey fg */ vidptr = 0x07; ++j; i = i + 2; } return; }

Всё, что сделает наше ядро - очистит экран и выведет строку “my first kernel”.

Сперва мы создаём указатель vidptr , который указывает на адрес 0xb8000 . С этого адреса в защищённом режиме начинается “видеопамять”. Для вывода текста на экран мы резервируем 25 строк по 80 ASCII-символов, начиная с 0xb8000.

Каждый символ отображается не привычными 8 битами, а 16. В первом байте хранится сам символ, а во втором - attribute-byte . Он описывает форматирование символа, например, его цвет.

Для вывода символа s зелёного цвета на чёрном фоне мы запишем этот символ в первый байт и значение 0x02 во второй. 0 означает чёрный фон, 2 - зелёный цвет текста.

Вот таблица цветов:

0 - Black, 1 - Blue, 2 - Green, 3 - Cyan, 4 - Red, 5 - Magenta, 6 - Brown, 7 - Light Grey, 8 - Dark Grey, 9 - Light Blue, 10/a - Light Green, 11/b - Light Cyan, 12/c - Light Red, 13/d - Light Magenta, 14/e - Light Brown, 15/f – White.

В нашем ядре мы будем использовать светло-серый текст на чёрном фоне, поэтому наш байт-атрибут будет иметь значение 0x07.

В первом цикле программа выводит пустой символ по всей зоне 80×25. Это очистит экран. В следующем цикле в “видеопамять” записываются символы из нуль-терминированной строки “my first kernel” с байтом-атрибутом, равным 0x07. Это выведет строку на экран.

Связующая часть

Мы должны собрать kernel.asm в объектный файл, используя NASM; затем при помощи GCC скомпилировать kernel.c в ещё один объектный файл. Затем их нужно присоединить к исполняемому загрузочному ядру.

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

/* * link.ld */ OUTPUT_FORMAT(elf32-i386) ENTRY(start) SECTIONS { . = 0x100000; .text: { *(.text) } .data: { *(.data) } .bss: { *(.bss) } }

Сперва мы зададим формат вывода как 32-битный Executable and Linkable Format (ELF). ELF - это стандарный формат бинарных файлов Unix-систем архитектуры x86. ENTRY принимает один аргумент, определяющий имя символа, являющегося точкой входа. SECTIONS - это самая важная часть. В ней определяется разметка нашего исполняемого файла. Мы определяем, как должны соединяться разные секции и где их разместить.

В скобках после SECTIONS точка (.) отображает счётчик положения, по умолчанию равный 0x0. Его можно изменить, что мы и делаем.

Смотрим на следующую строку: .text: { *(.text) } . Звёздочка (*) - это специальный символ, совпадающий с любым именем файла. Выражение *(.text) означает все секции.text из всех входных файлов.

Таким образом, линковщик соединяет все секции кода объектных файлов в одну секцию исполняемого файла по адресу в счётчике положения (0x100000). После этого значение счётчика станет равным 0x100000 + размер полученной секции.

Аналогично всё происходит и с другим секциями.

Grub и Multiboot

Теперь все файлы готовы к созданию ядра. Но остался ещё один шаг.

Существует стандарт загрузки x86-ядер с использованием бутлоадера, называющийся Multiboot specification . GRUB загрузит наше ядро, только если оно удовлетворяет этим спецификациям .

Следуя им, ядро должно содержать заголовок в своих первых 8 килобайтах. Кроме того, этот заголовок должен содержать 3 поля, являющихся 4 байтами:

  • магическое поле: содержит магическое число 0x1BADB002 для идентификации ядра.
  • поле flags : нам оно не нужно, установим в ноль.
  • поле checksum : если сложить его с предыдущими двумя, должен получиться ноль.

Наш kernel.asm станет таким:

;;kernel.asm ;nasm directive - 32 bit bits 32 section .text ;multiboot spec align 4 dd 0x1BADB002 ;magic dd 0x00 ;flags dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero global start extern kmain ;kmain is defined in the c file start: cli ;block interrupts mov esp, stack_space ;set stack pointer call kmain hlt ;halt the CPU section .bss resb 8192 ;8KB for stack stack_space:

Строим ядро

Теперь мы создадим объектные файлы из kernel.asm и kernel.c и свяжем их, используя наш скрипт.

Nasm -f elf32 kernel.asm -o kasm.o

Эта строка запустит ассемблер для создания объектного файла kasm.o в формате ELF-32.

Gcc -m32 -c kernel.c -o kc.o

Опция “-c” гарантирует, что после компиляции не произойдёт скрытого линкования.

Ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o

Это запустит линковщик с нашим скриптом и создаст исполняемый файл, называющийся kernel .

Настраиваем grub и запускаем ядро

GRUB требует, чтобы имя ядра удовлетворяло шаблону kernel- . Поэтому переименуйте ядро. Своё я назвал kernel-701.

Теперь поместите его в директорию /boot . Для этого понадобятся права суперпользователя.

В конфигурационном файле GRUB grub.cfg добавьте следующее:

Title myKernel root (hd0,0) kernel /boot/kernel-701 ro

Не забудьте убрать директиву hiddenmenu , если она есть.

Перезагрузите компьютер, и вы увидите список ядер с вашим в том числе. Выберите его, и вы увидите:

Это ваше ядро! В добавим систему ввода / вывода.

P.S.

  • Для любых фокусов с ядром лучше использовать виртуальную машину.
  • Для запуска ядра в grub2 конфиг должен выглядеть так: menuentry "kernel 7001" { set root="hd0,msdos1" multiboot /boot/kernel-7001 ro }
  • если вы хотите использовать эмулятор qemu , используйте: qemu-system-i386 -kernel kernel

рТЙЧЕФУФЧХА ЧУЕИ УЧПЙИ ЮЙФБФЕМЕК!

рТЕДЩДХЭЙЕ ЧЩРХУЛЙ НПЗМЙ ВЩФШ ОЕУЛПМШЛП ЪБРХФБООЩНЙ. оБЮБМШОБС ЪБЗТХЪЛБ, Assembler, BIOS. уЕЗПДОС НЩ ОБЛПОЕГ РЕТЕИПДЙН Л ВПМЕЕ ЙОФЕТЕУОПК Й РПОСФОПК ЮБУФЙ - НЩ ОБЮЙОБЕН РЙУБФШ СДТП. й РЙУБФШ НЩ ЕЗП ВХДЕН ОБ СЪЩЛЕ ЧЩУПЛПЗП ХТПЧОС уЙ.

ч ОБЮБМШОЩК ЪБЗТХЪЮЙЛ ПУФБМПУШ ЧОЕУФЙ ЧУЕЗП РБТХ ДПРПМОЕОЙК Й ПО ВХДЕФ РПМОПУФША ЗПФПЧ ЗТХЪЙФШ МАВЩЕ 32-ВЙФОЩЕ СДТБ.

пРТЕДЕМЕОЙЕ ПВЯЈНБ ПРЕТБФЙЧОПК РБНСФЙ

лПОЕЮОП, НПЦОП РПДУЮЙФБФШ ПВЯЈН РБНСФЙ ЧТХЮОХА Ч СДТЕ - РЕТЕВЙТБФШ БДТЕУБ ПФ 0x100000 Й РЩФБФШУС ЪБРЙУБФШ ФХДБ ЪОБЮЕОЙЕ ПФМЙЮОПЕ ПФ ОХМС Й 0xFF. еУМЙ РТЙ ЮФЕОЙЙ НЩ РПМХЮБЕН РПМХЮЕООПЕ ЪОБЮЕОЙЕ, ФП ЧУЈ ИПТПЫП, ЙОБЮЕ РБНСФШ ЛПОЮЙМБУШ - ЪБРПНЙОБЕН БДТЕУ РПУМЕДОЕЗП ХДБЮОПЗП ЮФЕОЙС, ЬФП Й ВХДЕФ ПВЯЈНПН ПРЕТБФЙЧОПК РБНСФЙ. пДОБЛП ФБЛПК УРПУПВ ЙНЕЕФ ДЧБ ОЕДПУФБФЛБ:

1) еЗП УМЕДХЕФ ЙУРПМШЪПЧБФШ ДП ЧЛМАЮЕОЙС УФТБОЙЮОПК БДТЕУБГЙЙ, ЮФПВЩ ЙНЕФШ ДПУФХР ЛП ЧУЕК ЖЙЪЙЮЕУЛПК РБНСФЙ, МЙВП ХУФТБЙЧБФШ ЪБРЙУШ ЮЕТЕЪ "ПЛОП" ЧТЕНЕООПК УФТБОЙГЩ. мЙЫОСС ФТБФБ ЧТЕНЕОЙ, РТЙ ХУМПЧЙЙ, ЮФП ФЕУФЙТПЧБОЙЕ РБНСФЙ BIOS Й ФБЛ ЧЩРПМОСЕФ РТЙ ОБЮБМШОПК ЙОЙГЙБМЙЪБГЙЙ, Б НЩ ДЕМБЕН ДЧПКОХА ТБВПФХ.

2) чУЈ ИПТПЫП РПЛБ РБНСФШ РТЕДУФБЧМСЕФ УПВПК ОЕРТЕТЩЧОЩК ХЮБУФПЛ БДТЕУПЧ, ОП ОБ УПЧТЕНЕООЩИ УЙУФЕНБИ У ВПМШЫЙН ПВЯЈНПН РБНСФЙ ЬФП РТБЧЙМП НПЦЕФ ВЩФШ ОБТХЫЕОП. л ФПНХ ЦЕ BIOS РЙЫЕФ Ч УБНХА ПВЩЮОХА РБНСФШ ФБВМЙГЩ ACPI, ЛПФПТЩЕ РТЙЗПДСФУС ПРЕТБГЙПООПК УЙУФЕНЕ Й ОЕ УФПЙФ ЙИ ЪБФЙТБФШ ДП РТПЮФЕОЙС.

йЪ ЬФПЗП УМЕДХЕФ, ЮФП МХЮЫЕ УРТПУЙФШ РТП ПВЯЈН ПРЕТБФЙЧОПК РБНСФЙ Х BIOS, ВМБЗП ПО РТЕДПУФБЧМСЕФ ЧУЕ ОЕПВИПДЙНЩЕ ЖХОЛГЙЙ.

йУФПТЙЮЕУЛЙ РЕТЧПК ЖХОЛГЙЕК ПРТЕДЕМЕОЙС ПВЯЈНБ ПРЕТБФЙЧОПК РБНСФЙ ВЩМП РТЕТЩЧБОЙЕ 0x12. пОП ОЕ РТЙОЙНБЕФ ОЙЛБЛЙИ ЧИПДОЩИ РБТБНЕФТПЧ, Ч ОБ ЧЩИПДЕ Ч ТЕЗЙУФТЕ AX УПДЕТЦЙФУС ТБЪНЕТ ВБЪПЧПК РБНСФЙ Ч ЛЙМПВБКФБИ. вБЪПЧБС РБНСФШ - ФЕ УБНЩЕ 640 лв ДПУФХРОЩЕ Ч ТЕБМШОПН ТЕЦЙНЕ. уЕКЮБУ ЧЩ ХЦЕ ОЕ УНПЦЕФЕ ОБКФЙ ЛПНРШАФЕТ, ЗДЕ ВЩ ВЩМП НЕОЕЕ 640 лв РБНСФЙ, ОП НБМП МЙ. йУРПМШЪПЧБФШ ЕЈ ОБН УНЩУМБ ОЕФ - ЕУМЙ РТПГЕУУПТ РПДДЕТЦЙЧБЕФ ЪБЭЙЭЈООЩК ТЕЦЙН, ФП ЧТСД МЙ Х ОЕЗП ВХДЕФ НЕОШЫЕ ОЕУЛПМШЛЙИ НЕЗБВБКФ РБНСФЙ.

пВЯЈНЩ РБНСФЙ ТПУМЙ Й 640 лв УФБМП НБМП. фПЗДБ РПСЧЙМБУШ ОПЧБС ЖХОЛГЙС - РТЕТЩЧБОЙЕ 0x15 AH=0x88. пОБ ЧПЪЧТБЭБЕФ Ч AX ТБЪНЕТ ТБУЫЙТЕООПК РБНСФЙ (УЧЩЫЕ 1 нв) Ч ЛЙМПВБКФБИ Ч AX. ьФБ ЖХОЛГЙС ОЕ НПЦЕФ ЧПЪЧТБЭБФШ ЪОБЮЕОЙС ВПМШЫЕ 15 нв (15 + 1 ЙФПЗП 16 нв).

лПЗДБ Й 16 нв УФБМП ОЕДПУФБФПЮОП РПСЧЙМБУШ ОПЧБС ЖХОЛГЙС - РТЕТЩЧБОЙЕ 0x15, AX=0xE801. пОБ ЧПЪЧТБЭБЕФ ТЕЪХМШФБФЩ БЦ Ч 4 ТЕЗЙУФТБИ:

AX - ТБЪНЕТ ТБУЫЙТЕООПК РБНСФЙ ДП 16 нв Ч ЛЙМПВБКФБИ
BX - ТБЪНЕТ ТБУЫЙТЕООПК РБНСФЙ УЧЕТИ 16 нв Л ВМПЛБИ РП 64 лв
CX - ТБЪНЕТ УЛПОЖЙЗХТЙТПЧБООПК ТБУЫЙТЕООПК РБНСФЙ ДП 16 нв Ч ЛЙМПВБКФБИ
DX - ТБЪНЕТ УЛПОЖЙЗХТЙТПЧБООПК ТБУЫЙТЕООПК РБНСФЙ УЧЕТИ 16 нв Ч ВМПЛБИ РП 64 лв

юФП ФБЛПЕ "УЛПОЖЙЗХТЙТПЧБООБС" РБНСФШ РТПЙЪЧПДЙФЕМЙ BIOS УХДС РП ЧУЕНХ ОЕ ДПЗПЧПТЙМЙУШ, РПЬФПНХ ОБДП РТПУФП, ЕУМЙ Ч AX Й BX ОХМЙ, ВТБФШ ЪОБЮЕОЙЕ ЙЪ CX Й DX.

оП Й ЬФПЗП ПЛБЪБМПУШ НБМП. чЕДШ ЧУЕ РЕТЕЮЙУМЕООЩЕ ЧЩЫЕ ЖХОЛГЙЙ ЙНЕАФ ПЗТБОЙЮЕОЙЕ ПВЯЈНБ РБНСФЙ Ч 4 зв, Л ФПНХ ЦЕ ОЕ ХЮЙФЩЧБАФ ФП, ЮФП РБНСФШ НПЦЕФ ВЩФШ ОЕ ОЕРТЕТЩЧОЩН ВМПЛПН. рПЬФПНХ Ч ОПЧЩИ BIOS РПСЧЙМБУШ ЕЭЈ ПДОБ ЖХОЛГЙС - РТЕТЩЧБОЙЕ 0x15, AX=0xE820. пОБ ЧПЪЧТБЭБЕФ ОЕ РТПУФП ЮЙУМП, Б ЛБТФХ РБНСФЙ. чИПДОЩЕ РБТБНЕФТЩ:

EAX=0xE820
EDX=0x534D4150 ("SMAP")
EBX - УНЕЭЕОЙЕ ПФ ОБЮБМБ ЛБТФЩ РБНСФЙ (ДМС ОБЮБМБ 0)
ECX - ТБЪНЕТ ВХЖЕТБ (ЛБЛ РТБЧЙМП 24 ВБКФБ - ТБЪНЕТ ПДОПЗП ЬМЕНЕОФБ)
ES:DI - БДТЕУ ВХЖЕТБ, ЛХДБ ОБДП ЪБРЙУБФШ ПЮЕТЕДОПК ЬМЕНЕОФ

чЩИПДОЩЕ РБТБНЕФТЩ:

EAX=0x534D4150 ("SMAP")
EBX - ОПЧПЕ УНЕЭЕОЙЕ ДМС УМЕДХАЭЕЗП ЧЩЪПЧБ ЖХОЛГЙЙ. еУМЙ 0, ФП ЧУС ЛБТФБ РБНСФЙ РТПЮЙФБОБ
ECX - ЛПМЙЮЕУФЧП ТЕБМШОП ЧПЪЧТБЭЈООЩИ ВБКФ (20 ЙМЙ 24 ВБКФБ)
ч ХЛБЪБООПН ВХЖЕТЕ УПДЕТЦЙФУС ПЮЕТЕДОПК ЬМЕНЕОФ ЛБТФЩ РБНСФЙ.

лБЦДЩК ЬМЕНЕОФ ЛБТФЩ РБНСФЙ ЙНЕЕФ УМЕДХАЭХА УФТХЛФХТХ (ОБРЙЫХ Ч УЙОФБЛУЙУЕ уЙ, РПФПНХ ЮФП ТБЪВПТ ДБООЩИ НЩ ВХДЕН ДЕМБФШ ХЦЕ Ч СДТЕ):

Struct { unsigned long long base; //вБЪПЧЩК ЖЙЪЙЮЕУЛЙК БДТЕУ ТЕЗЙПОБ unsigned long long length; //тБЪНЕТ ТЕЗЙПОБ Ч ВБКФБИ unsigned long type; // фЙР ТЕЗЙПОБ unsigned long acpi_attrs; //тБУЫЙТЕООЩЕ БФТЙВХФЩ ACPI };

рПУМЕДОЙК ЬМЕНЕОФ УФТХЛФХТЩ ОЕ ПВСЪБФЕМЕО. еЭЈ Ч ПДОПН ЙУФПЮОЙЛЕ ЧЙДЕМ, ЮФП РЕТЕД ЪБРТПУПН ЬМЕНЕОФБ УФПЙФ РПНЕУФЙФШ ФХДБ ЕДЙОЙЮЛХ. лПОЕЮОП, УЕКЮБУ НЩ ОЕ РПДДЕТЦЙЧБЕН ACPI, ОП МХЮЫЕ ЪБТБОЕЕ РПЪБВПФЙФУС П ФПН, ЮФПВЩ РПМХЮЙФШ ЛБЛ НПЦОП ВПМШЫЕ ДБООЩИ. ч ПФМЙЮЙЙ ПФ РБТБНЕФТПЧ РБНСФЙ, ЧУЈ ПУФБМШОПЕ НПЦОП МЕЗЛП ХЪОБФШ Й ЙЪ ЪБЭЙЭЈООПЗП ТЕЦЙНБ ОБРТСНХА, ВЕЪ BIOS.

тЕЗЙПОЩ РБНСФЙ, ПРЙУЩЧБЕНЩЕ ЛБТФПК, НПЗХФ ВЩФШ ОЕУЛПМШЛЙИ ФЙРПЧ:

1 - пВЩЮОБС РБНСФШ. нПЦЕФ ВЩФШ УЧПВПДОП ЙУРПМШЪПЧБОБ пу ДМС УЧПЙИ ГЕМЕК. рПЛБ НЩ ФПМШЛП Л ОЕК Й ВХДЕН ПВТБЭБФШУС, Б ЧУЈ ПУФБМШОПЕ РТПРХУЛБФШ.
2 - ъБТЕЪЕТЧЙТПЧБОП (ОБРТЙНЕТ, ЛПД BIOS). ьФБ РБНСФШ НПЦЕФ ВЩФШ ЛБЛ ЖЙЪЙЮЕУЛЙ ОЕДПУФХРОБ ДМС ЪБРЙУЙ, ФБЛ Й РТПУФП ЪБРЙУШ ФХДБ ОЕЦЕМБФЕМШОБ. фБЛХА РБНСФШ МХЮЫЕ ОЕ ФТПЗБФШ.
3 - дПУФХРОП РПУМЕ РТПЮФЕОЙС ФБВМЙГ ACPI. чЕТПСФОП, ЙНЕООП Ч ЬФЙИ ВМПЛБИ ЬФЙ ФБВМЙГЩ Й ИТБОСФУС. рПЛБ ДТБКЧЕТ ACPI ОЕ РТПЮЙФБЕФ ФБВМЙГЩ, ЬФХ РБНСФШ МХЮЫЕ ОЕ ФТПЗБФШ. рПФПН НПЦОП ЙУРПМШЪПЧБФШ ФБЛ ЦЕ, ЛБЛ Й РБНСФШ ФЙРБ 1.
4 - ьФХ РБНСФШ УМЕДХЕФ УПИТБОСФШ НЕЦДХ NVS УЕУУЙСНЙ. фБЛХА РБНСФШ НЩ ФТПЗБФШ ОЕ ВХДЕН, РПЛБ ОЕ ХЪОБЕН, ЮФП ФБЛПЕ NVS УЕУУЙЙ:-)

оЕ ЧУЕ BIOS НПЗХФ РПДДЕТЦЙЧБФШ ЬФХ ЖХОЛГЙА. еУМЙ ЛБЛБС-ФП ЖХОЛГЙС ОЕ РПДДЕТЦЙЧБЕФУС, ФП РТЙ ЧЩИПДЕ ЙЪ ОЕЈ ХУФБОПЧМЕО ЖМБЗ РЕТЕРПМОЕОЙС Й УМЕДХЕФ ПВТБЭБФШУС Л ВПМЕЕ УФБТПК. нЩ ВХДЕН ЙУРПМШЪПЧБФШ ЖПТНБФ ЛБТФЩ РБНСФЙ ЖХОЛГЙЙ 0xE820. еУМЙ УБНХ ЬФХ ЖХОЛГЙА ЧЩЪЧБФШ ОЕ РПМХЮЙМПУШ - РПМХЮБФШ ПВЯЈН РБНСФЙ ПВЩЮОЩНЙ УТЕДУФЧБНЙ Й УПЪДБЧБФШ УЧПА УПВУФЧЕООХА ЛБТФХ РБНСФЙ ЙЪ ПДОПЗП ЬМЕНЕОФБ. рПУЛПМШЛХ ПРТЕДЕМЕОЙЕ ПВЯЈНБ РБНСФЙ ЪБДБЮБ ОХЦОБС Й ДМС ЪБРХУЛБ 32-ВЙФОПЗП Й ДМС ЪБРХУЛБ 64-ВЙФОПЗП СДТБ, МХЮЫЕ ПЖПТНЙФШ ЕЈ Ч ЧЙДЕ РПДРТПЗТБННЩ. лБТФХ РБНСФЙ ТБЪНЕУФЙН РП БДТЕУХ 0x7000. оЕ ДХНБА, ЮФП ПОБ НПЦЕФ ВЩФШ ВПМШЫЕ РБТЩ ЛЙМПВБКФ. рПУМЕДОЙК ЬМЕНЕОФ ЧТХЮОХА УДЕМБЕН ФЙРБ 0 - ФБЛПЗП ФЙРБ ОЕ ЧПЪЧТБЭБЕФ BIOS Й ЬФП Й ВХДЕФ РТЙЪОБЛПН ЛПОГБ.

; рПМХЮЕОЙЕ ЛБТФЩ РБНСФЙ get_memory_map: mov di, 0x7000 xor ebx, ebx @: mov eax, 0xE820 mov edx, 0x534D4150 mov ecx, 24 mov dword, 1 int 0x15 jc @f add di, 24 test ebx, ebx jnz @b @: cmp di, 0x7000 ja .ok mov dword, 0x100000 mov dword, 0 mov dword, 0 mov dword, 1 mov dword, 0 mov ax, 0xE801 int 0x15 jnc @f mov ah, 0x88 int 0x15 jc .ok mov cx, ax xor dx, dx @: test cx, cx jz @f mov ax, cx mov bx, dx @: movzx eax, ax movzx ebx, bx mov ecx, 1024 mul ecx push eax mov eax, ebx mov ecx, 65536 mul ecx pop edx add eax, edx mov , eax add di, 24 jmp .ok .ok: xor ax, ax mov cx, 24 / 2 rep stosw ret

оХ ЧПФ Й ЗПФПЧ ОБЫ ОБЮБМШОЩК ЪБЗТХЪЮЙЛ ДМС 32-ВЙФОЩИ СДЕТ. ч ЪБЛМАЮЕОЙЕ РТЙЧПЦХ ЕЗП РПМОЩК ЛПД Й НЩ РЕТЕКДЈН Л СДТХ.

; оБЮБМШОЩК ЪБЗТХЪЮЙЛ СДТБ ДМС БТИЙФЕЛФХТЩ x86 format Binary as "bin" org 0x7C00 jmp boot ; ъБЗПМПЧПЛ ListFS align 4 fs_magic dd ? fs_version dd ? fs_flags dd ? fs_base dq ? fs_size dq ? fs_map_base dq ? fs_map_size dq ? fs_first_file dq ? fs_uid dq ? fs_block_size dd ? ; ъБЗПМПЧПЛ ЖБКМБ virtual at 0x800 f_info: f_name rb 256 f_next dq ? f_prev dq ? f_parent dq ? f_flags dq ? f_data dq ? f_size dq ? f_ctime dq ? f_mtime dq ? f_atime dq ? end virtual ; дБООЩЕ ОБЮБМШОПЗП ЪБЗТХЪЮЙЛБ label sector_per_track word at $$ label head_count byte at $$ + 2 label disk_id byte at $$ + 3 reboot_msg db "Press any key...",13,10,0 boot_file_name db "boot.bin",0 ; чЩЧПД УФТПЛЙ DS:SI ОБ ЬЛТБО write_str: push si mov ah, 0x0E @: lodsb test al, al jz @f int 0x10 jmp @b @: pop si ret ; лТЙФЙЮЕУЛБС ПЫЙВЛБ error: pop si call write_str ; рЕТЕЪБЗТХЪЛБ reboot: mov si, reboot_msg call write_str xor ah, ah int 0x16 jmp 0xFFFF:0 ; ъБЗТХЪЛБ УЕЛФПТБ DX:AX Ч ВХЖЕТ ES:DI load_sector: push dx add ax, word adc dx, word cmp byte, 0xFF je .use_EDD push bx cx si div mov cl, dl inc cl div mov dh, ah mov ch, al mov dl, mov bx, di mov al, 1 mov si, 3 @: mov ah, 2 int 0x13 jnc @f xor ah, ah int 0x13 dec si jnz @b .error: call error db "DISK ERROR",13,10,0 @: pop si cx bx dx ret .use_EDD: push si mov byte, 0x10 mov byte, 0 mov word, 1 mov , di push es pop word mov , ax mov , dx mov word, 0 mov word, 0 mov ah, 0x42 mov dl, mov si, 0x600 int 0x13 jc .error pop si dx ret ; рПЙУЛ ЖБКМБ У ЙНЕОЕН DS:SI Ч ЛБФБМПЗЕ DX:AX find_file: push cx dx di .find: cmp ax, -1 jne @f cmp dx, -1 jne @f .not_found: call error db "NOT FOUND",13,10,0 @: mov di, f_info call load_sector push di mov cx, 0xFFFF xor al, al repne scasb neg cx dec cx pop di push si repe cmpsb pop si je .found mov ax, word mov dx, word jmp .find .found: pop di dx cx ret ; ъБЗТХЪЛБ ФЕЛХЭЕЗП ЖБКМБ Ч РБНСФШ РП БДТЕУХ BX:0. лПМЙЮЕУФЧП ЪБЗТХЦЕООЩИ УЕЛФПТПЧ ЧПЪЧТБЭБЕФУС Ч AX load_file_data: push bx cx dx si di mov ax, word mov dx, word .load_list: cmp ax, -1 jne @f cmp dx, -1 jne @f .file_end: pop di si dx cx mov ax, bx pop bx sub ax, bx shr ax, 9 - 4 ret @: mov di, 0x8000 / 16 call load_sector mov si, di mov cx, 512 / 8 - 1 .load_sector: lodsw mov dx, add si, 6 cmp ax, -1 jne @f cmp dx, -1 je .file_end @: push es mov es, bx xor di, di call load_sector add bx, 0x200 / 16 pop es loop .load_sector lodsw mov dx, jmp .load_list ; фПЮЛБ ЧИПДБ Ч ОБЮБМШОЩК ЪБЗТХЪЮЙЛ boot: ; оБУФТПЙН УЕЗНЕОФОЩЕ ТЕЗЙУФТЩ jmp 0:@f @: mov ax, cs mov ds, ax mov es, ax ; оБУФТПЙН УФЕЛ mov ss, ax mov sp, $$ ; тБЪТЕЫЙН РТЕТЩЧБОЙС sti ; ъБРПНОЙН ОПНЕТ ЪБЗТХЪПЮОПЗП ДЙУЛБ mov , dl ; пРТЕДЕМЙН РБТБНЕФТЩ ЪБЗТХЪПЮОПЗП ДЙУЛБ mov ah, 0x41 mov bx, 0x55AA int 0x13 jc @f mov byte, 0xFF jmp .disk_detected @: mov ah, 0x08 xor di, di push es int 0x13 pop es jc load_sector.error inc dh mov , dh and cx, 111111b mov , cx .disk_detected: ; ъБЗТХЪЙН РТПДПМЦЕОЙЕ ОБЮБМШОПЗП ЪБЗТХЪЮЙЛБ mov si, boot_file_name mov ax, word mov dx, word call find_file mov bx, 0x7E00 / 16 call load_file_data ; рЕТЕИПДЙН ОБ РТПДПМЦЕОЙЕ jmp boot2 ; рХУФПЕ РТПУФТБОУФЧП Й УЙЗОБФХТБ rb 510 - ($ - $$) db 0x55,0xAA ; дПРПМОЙФЕМШОЩЕ ДБООЩЕ ЪБЗТХЪЮЙЛБ load_msg_preffix db "Loading "",0 load_msg_suffix db ""...",0 ok_msg db "OK",13,10,0 config_file_name db "boot.cfg",0 start16_msg db "Starting 16 bit kernel...",13,10,0 start32_msg db "Starting 32 bit kernel...",13,10,0 label module_list at 0x6000 label memory_map at 0x7000 ; тБЪВЙЕОЙЕ УФТПЛЙ DS:SI РП УЙНЧПМХ УМЕЫБ split_file_name: push si @: lodsb cmp al, "/" je @f test al, al jz @f jmp @b @: mov byte, 0 mov ax, si pop si ret ; ъБЗТХЪЛБ ЖБКМБ У ЙНЕОЕН DS:SI Ч ВХЖЕТ BX:0. тБЪНЕТ ЖБКМБ Ч УЕЛФПТБИ ЧПЪЧТБЭБЕФУС Ч AX load_file: push si mov si, load_msg_preffix call write_str pop si call write_str push si mov si, load_msg_suffix call write_str pop si push si bp mov dx, word mov ax, word @: push ax call split_file_name mov bp, ax pop ax call find_file test byte, 1 jz @f mov si, bp mov dx, word mov ax, word jmp @b @: call load_file_data mov si, ok_msg call write_str pop bp si ret ; рПМХЮЕОЙЕ ЛБТФЩ РБНСФЙ get_memory_map: mov di, memory_map xor ebx, ebx @: mov eax, 0xE820 mov edx, 0x534D4150 mov ecx, 24 mov dword, 1 int 0x15 jc @f add di, 24 test ebx, ebx jnz @b @: cmp di, 0x7000 ja .ok mov dword, 0x100000 mov dword, 0 mov dword, 0 mov dword, 1 mov dword, 0 mov ax, 0xE801 int 0x15 jnc @f mov ah, 0x88 int 0x15 jc .ok mov cx, ax xor dx, dx @: test cx, cx jz @f mov ax, cx mov bx, dx @: movzx eax, ax movzx ebx, bx mov ecx, 1024 mul ecx push eax mov eax, ebx mov ecx, 65536 mul ecx pop edx add eax, edx mov , eax add di, 24 jmp .ok .ok: xor ax, ax mov cx, 24 / 2 rep stosw ret ; рТПДПМЦЕОЙЕ ОБЮБМШОПЗП ЪБЗТХЪЮЙЛБ boot2: ; ъБЗТХЪЙН ЛПОЖЙЗХТБГЙПООЩК ЖБКМ ЪБЗТХЪЮЙЛБ mov si, config_file_name mov bx, 0x1000 / 16 call load_file ; чЩРПМОЙН ЪБЗТХЪПЮОЩК УЛТЙРФ mov bx, 0x9000 / 16 mov bp, module_list mov dx, 0x1000 .parse_line: mov si, dx .parse_char: lodsb test al, al jz .config_end cmp al, 10 je .run_command cmp al, 13 je .run_command jmp .parse_char .run_command: mov byte, 0 xchg dx, si cmp byte, 0 je .parse_line ; рХУФБС УФТПЛБ cmp byte, "#" je .parse_line ; лПННЕОФБТЙК cmp byte, "L" je .load_file ; ъБЗТХЪЛБ ЖБКМБ cmp byte, "S" je .start ; ъБРХУЛ СДТБ; оЕЙЪЧЕУФОБС ЛПНБОДБ mov al, mov [.cmd], al call error db "Unknown boot script command "" .cmd db ? db ""!",13,10,0 .config_end: ; рТЙ РТБЧЙМШОПН ЛПОЖЙЗХТБГЙПООПН ЖБКМЕ НЩ ОЕ ДПМЦОЩ УАДБ РПРБУФШ; ъБЧЕТЫЕОЙЕ jmp reboot ; ъБЗТХЪЛБ ЖБКМБ.load_file: push dx inc si call load_file push ax mov cx, 512 mul cx mov word, ax mov word, dx mov word, 0 mov word, 0 mov ax, bx mov cx, 16 mul cx mov word, ax mov word, dx mov word, 0 mov word, 0 pop ax shr ax, 9 - 4 add bx, ax add bp, 16 pop dx jmp .parse_line ; ъБРХУЛ СДТБ.start: ; рТПЧЕТЙН, ЮФП ЪБЗТХЦЕО ИПФС ВЩ ПДЙО ЖБКМ cmp bx, 0x9000 / 16 ja @f call error db "NO KERNEL LOADED",13,10,0 @: ; ъБРПМОСЕН РПУМЕДОЙК ЬМЕНЕОФ УРЙУЛБ ЖБКМПЧ xor ax, ax mov cx, 16 mov di, bp rep stosw ; рЕТЕИПДЙН Л РТПГЕДХТЕ ЙОЙГЙБМЙЪБГЙЙ СДТБ ДМС ОХЦОПК ТБЪТСДОПУФЙ inc si cmp word, "16" je .start16 cmp word, "32" je .start32 ;cmp word, "64" ;je .start64 ; оЕЙЪЧЕУФОБС ТСЪТСДОПУФШ СДТБ call error db "Invalid start command argument",13,10,0 ; ъБРХУЛ 16-ТБЪТСДОПЗП СДТБ.start16: mov si, start16_msg mov bx, module_list mov dl, jmp 0x9000 ; ъБРХУЛ 32-ТБЪТСДОПЗП СДТБ.start32: ; чЩЧПДЙН ХЧЕДПНМЕОЙЕ П ЪБРХУЛЕ 32-ВЙФОПЗП СДТБ mov si, start32_msg call write_str ; рТПЧЕТЙН, ЮФП РТПГЕУУПТ ОЕ ИХЦЕ i386 mov ax, 0x7202 push ax popf pushf pop bx cmp ax, bx je @f call error db "Required i386 or better",13,10,0 @: ; рПМХЮЙН ЛБТФХ РБНСФЙ call get_memory_map ; пЮЙУФЙН ФБВМЙГЩ УФТБОЙГ xor ax, ax mov cx, 3 * 4096 / 2 mov di, 0x1000 rep stosw ; ъБРПМОЙН ЛБФБМПЗ УФТБОЙГ mov word, 0x2000 + 111b mov word, 0x3000 + 111b ; ъБРПМОЙН РЕТЧХА ФБВМЙГХ УФТБОЙГ mov eax, 11b mov cx, 0x100000 / 4096 mov di, 0x2000 @: stosd add eax, 0x1000 loop @b ; ъБРПМОЙН РПУМЕДОАА ФБВМЙГХ УФТБОЙГ mov di, 0x3000 mov eax, dword or eax, 11b mov ecx, dword shr ecx, 12 @: stosd add eax, 0x1000 loop @b mov word, 0x4000 + 11b ; Kernel stack mov word, 0x3000 + 11b ; Kernel page table ; ъБЗТХЪЙН ЪОБЮЕОЙЕ Ч CR3 mov eax, 0x1000 mov cr3, eax ; ъБЗТХЪЙН ЪОБЮЕОЙЕ Ч GDTR lgdt ; ъБРТЕФЙН РТЕТЩЧБОЙС cli ; рЕТЕКДЈН Ч ЪБЭЙЭЈООЩК ТЕЦЙН mov eax, cr0 or eax, 0x80000001 mov cr0, eax ; рЕТЕКДЈН ОБ 32-ВЙФОЩК ЛПД jmp 8:start32 ; фБВМЙГБ ДЕУЛТЙРФПТПЧ УЕЗНЕОФПЧ ДМС 32-ВЙФОПЗП СДТБ align 16 gdt32: dq 0 ; NULL - 0 dq 0x00CF9A000000FFFF ; CODE - 8 dq 0x00CF92000000FFFF ; DATA - 16 gdtr32: dw $ - gdt32 - 1 dd gdt32 ; 32-ВЙФОЩК ЛПД use32 start32: ; оБУФТПЙН УЕЗНЕОФОЩЕ ТЕЗЙУФТЩ Й УФЕЛ mov eax, 16 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax mov esp, 0xFFFFDFFC ; рПНЕУФЙН Ч DL ОПНЕТ ЪБЗТХЪПЮОПЗП ДЙУЛБ mov dl, ; рПНЕУФЙН Ч EBX БДТЕУ УРЙУЛБ ЪБЗТХЦЕООЩИ ЖБКМПЧ mov ebx, module_list ; рПНЕУФЙН Ч ESI БДТЕУ ЛБТФЩ РБНСФЙ mov esi, memory_map ; рЕТЕИПДЙН ОБ СДТП jmp 0xFFC00000

рЕТЧПЕ СДТП

сДТП РПЛБ Х ОБУ ВХДЕФ УПУФПСФШ ЙЪ ДЧХИ ЖБКМПЧ - startup.asm Й main.c. startup.asm ОХЦЕО ДМС ФПЗП, ЮФПВЩ ВЩФШ ХЧЕТЕООЩНЙ, ЮФП ХРТБЧМЕОЙЕ РПРБДЈФ ОБ ЖХОЛГЙА kernel_main. чЕДШ ПОБ НПЦЕФ ВЩФШ ОЕ Ч ОБЮБМЕ ЖБКМБ, Б УПДЕТЦЙНПЕ startup.o НЩ РПМОПУФША ЛПОФТПМЙТХЕН Й ЕУМЙ ХЛБЦЕН ЕЗП РЕТЧЩН МЙОЛЕТХ, ФП ВХДЕН ХРТБЧМСФШ Й РЕТЧЩНЙ ВБКФБНЙ ДЧПЙЮОПЗП ЖБКМБ.

Format ELF public _start extrn kernel_main section ".text" executable _start: movzx edx, dl push edx push esi push ebx lgdt call kernel_main @: ;cli ;hlt jmp @b section ".data" writable gdt: dq 0 dq 0x00CF9A000000FFFF dq 0x00CF92000000FFFF gdtr: dw $ - gdt dd gdt

оХ ЧПФ Й РПУМЕДОЙК ОБЫ ЛПД ОБ ЮЙУФПН Assembler:-). пО ЧЩРПМОСЕФ РТПУФЕКЫХА ЪБДБЮХ - ХМПЦЙФШ Ч УФЕЛ ФТЙ БТЗХНЕОФБ ДМС ЖХОЛГЙЙ kernel_main Й РЕТЕДБФШ ОБ ОЕЈ ХРТБЧМЕОЙЕ. рПУМЕ ЧПЪЧТБФБ ЙЪ ОЕЈ СДТП ХИПДЙФ Ч ВЕУЛПОЕЮОЩК ГЙЛМ. рП УПЗМБЫЕОЙА ЧЩЪПЧБ ЖХОЛГЙК уЙ РБТБНЕФТЩ УМЕДХЕФ РЙИБФШ Ч УФЕЛ Ч ПВТБЪПН РПТСДЛЕ. фБЛЦЕ ЬФПФ ЛПД ЙОЙГЙБМЙЪБГЙЙ ЪБЗТХЦБЕФ ОПЧПЕ ЪОБЮЕОЙЕ Ч GDTR - ФЕРЕТШ ФБВМЙГБ ДЕУЛТЙРФПТПЧ УЕЗНЕОФПЧ ОБИПДЙФУС Ч РТПУФТБОУФЧЕ СДТБ Й ДБЦЕ ЕУМЙ НЩ ПФНПОФЙТХЕН РЕТЧЩК НЕЗБВБКФ ОЕ РТПЙЪПКДЈФ ОЙЛБЛЙИ ПЫЙВПЛ.

б ФЕРЕТШ УБНПЕ ЧЛХУОПЕ - РТПУФЕКЫЕЕ СДТП ОБ СЪЩЛЕ ЧЩУПЛПЗП ХТПЧОС:

Typedef struct { unsigned long long base; unsigned long long size; } BootModuleInfo; void kernel_main(char boot_disk_id, void *memory_map, BootModuleInfo *boot_module_list) { char *screen_buffer = (void*)0xB8000; char *msg = "Hello world!"; unsigned int i = 24 * 80; while (*msg) { screen_buffer = *msg; msg++; i++; } }

ьФП СДТП ОЕ ДЕМБЕФ ОЙЮЕЗП ПУПВЕООПЗП - РТПУФП ЧЩЧПДЙФ УФТПЛХ "Hello world!" ОБ РПУМЕДОАА УФТПЮЛХ ФЕЛУФПЧПЗП ЬЛТБОБ. уФТХЛФХТБ ПРЙУБООБС Ч ОБЮБМЕ ВХДЕФ ОХЦОБ ДМС ДПУФХРБ Л УРЙУЛХ ЪБЗТХЦЕООЩИ НПДХМЕК.

чБЦОП РПНОЙФШ, ЮФП ОЙЛБЛПК УФБОДБТФОПК ВЙВМЙПФЕЛЙ Х ОБУ ОЕФ - ОБН ДПУФХРОЩ ФПМШЛП ФЕ ЖХОЛГЙЙ, ЛПФПТЩЕ НЩ УДЕМБЕН УБНЙ. чУЕ printf, strcpy, memcpy Й Ф. Р. РТЙДЈФУС ТЕБМЙЪПЧЩЧБФШ УБНПУФПСФЕМШОП, ОЕ РЩФБКФЕУШ ПВТБФЙФШУС Л ОЙН. ч УМЕДХАЭЕН ЧЩРХУЛЕ НЩ ЪБКНЈНУС УПЪДБОЙЕН ОБЫЕЗП УПВУФЧЕООПЗП ЦХФЛП ХТЕЪБООПЗП БОБМПЗБ libc, ЮФПВЩ РТПЗТБННЙТПЧБФШ ВЩМП ХДПВОЕЕ. фХФ ОБЮЙОБЕФУС УБНБС ЙОФЕТЕУОБС ЮБУФШ, Б РТЙОСФЩЕ ТЕЫЕОЙС ЧП НОПЗПН РПЧМЙСАФ ОБ ЧУА УФТХЛФХТХ УЙУФЕНЩ.

уВПТЛБ СДТБ

йУРПМОСЕНЩЕ ЖБКМЩ УПВЙТБАФУС Ч ДЧБ ЬФБРБ - ЛПНРЙМСГЙС, Б РПФПН МЙОЛПЧЛБ. оБ РЕТЧПН ЬФБРЕ ЛПНРЙМСФПТ РТЕПВТБЪХЕФ ЙУИПДОЩК ЛПД Ч ЛПНБОДЩ РТПГЕУУПТБ Й УПИТБОСЕФ ЧУЈ ЬФП Ч ПВЯЕЛФОЩК ЖБКМ. лБЦДЩК НПДХМШ УЙУФЕНЩ УПИТБОСЕФУС Ч ПФДЕМШОПН ЖБКМЕ. ч ЬФПН ЖБКМЕ ФБЛ ЦЕ УПДЕТЦЙФУС ЙОЖПТНБГЙС П ЖХОЛГЙСИ, ПРЙУБООЩИ Ч НПДХМЙ, РПЬФПНХ ЙЪ ПДОПЗП ЖБКМБ НПЦОП УЧПВПДОП ЧЩЪЩЧБФШ ЖХОЛГЙА ЙЪ ДТХЗПЗП. чЕУШ ЛПД Ч ПВЯЕЛФОЩИ ЖБКМБИ ОЕ РТЙЧСЪБО Л ЛПОЛТЕФОЩН БДТЕУБН. оБ ЧФПТПН ЬФБРЕ МЙОЛЕТ УПВЙТБЕФ ЧУЕ ПВЯЕЛФОЩЕ ЖБКМЩ Ч ПДЙО ВЙОБТОЩК. рТЙ ЬФПН ЛПД РТЙЧСЪЩЧБЕФУС Л ЛПОЛТЕФОЩН БДТЕУБН (ЕУМЙ, ЛПОЕЮОП, НЩ ОЕ УПВЙТБЕН ДЙОБНЙЮЕУЛЙ ЪБЗТХЦБЕНХА ВЙВМЙПФЕЛХ), ЧНЕУФП УУЩМПЛ ОБ ЖХОЛГЙЙ РПДУФБЧМСАФУС ОХЦОЩЕ БДТЕУБ. оБН ОХЦОП РПМХЮЙФШ ОБ ЧЩИПДЕ ПУПВЩК ДЧПЙЮОЩК ЖБКМ. ьФП РТПУФП ЛПД Й ДБООЩЕ, ВЕЪ ЛБЛЙИ-МЙВП ЪБЗПМПЧЛПЧ (ФП ЕУФШ ЬФП ОЕ PE Й ОЕ ELF). ч ЛБЮЕУФЧЕ ВБЪПЧПЗП БДТЕУБ ЙУРПМШЪХЕФУС БДТЕУ 0xFFC00000. дМС ХРТПЭЕОЙС ЬФПЗП НЩ ПРЙЫЕН ЧУЈ, ЮФП ОБН ОХЦОП Ч УРЕГЙБМШОПН ЖПТНБФЕ УЛТЙРФБ ld:

OUTPUT_FORMAT("binary") ENTRY(_start) SECTIONS { .text 0xFFC00000: { *(.text) *(.code) *(.rodata*) } .data ALIGN(0x1000) : { *(.data) } .bss ALIGN(0x1000) : { *(.bss) } .empty ALIGN(0x1000) - 1: { BYTE(0) } }

ьФПФ УЛТЙРФ ЗПЧПТЙФ, ЮФП ОБЫ ЖБКМ ВХДЕФ МЕЦБФШ Ч РБНСФЙ ОЕРТЕТЩЧОЩН ВМПЛПН ОБЮЙОБС У БДТЕУБ 0xFFC00000. ч УБНПН ОБЮБМЕ ВХДЕФ ЙДФЙ УЕЛГЙС ЛПДБ, РПФПН УЕЛГЙС read-only ДБООЩИ, ЪБФЕН ПВЩЮОЩИ ДБООЩИ, РПФПН ОЕЙОЙГЙБМЙЪЙТПЧБООЩИ. чУЕ УЕЛГЙЙ ЧЩТПЧОЕОЩ ОБ ТБЪНЕТ УФТБОЙГЩ 4 лв (ЧДТХЗ НЩ РПФПН ЪБИПФЙН ЪБЭЙФЙФШ ОБ ХТПЧОЕ ФБВМЙГЩ УФТБОЙГ ЛПД ПФ ЪБРЙУЙ). рПУМЕДОЕЕ ПРЙУБОЙЕ УЕЛГЙЙ.empty ОЕПВИПДЙНП ДМС ФПЗП, ЮФПВЩ ДБЦЕ ОЕЙОЙГЙБЙМЙЪПТПЧБООЩЕ РЕТЕНЕООЩЕ ЪБОЙНБМЙ НЕУФП Ч ЖБКМЕ (ФБН ВХДХФ ОХМЙ). чЕДШ ОБЮБМШОЩК ЪБЗТХЪЮЙЛ ЧЩДЕМСЕФ РБНСФШ ДМС СДТБ ТХЛПЧПДУФЧХСУШ ТБЪНЕТПН ЖБКМБ.

уПВТБФШ ЧУЈ СДТП НПЦОП УМЕДХАЭЙНЙ ЛПНБОДБНЙ:

Fasm startup.asm startup.o gcc -c -m32 -ffreestanding -o main.o main.c ld --oformat=binary -melf_i386 -T script.ld -o kernel.bin startup.o main.o

рБТБНЕФТ GCC -ffreestanding ХЛБЪЩЧБЕФ ЕНХ ПФЛМАЮЙФШ ЧУЕ УФБОДБТФОЩЕ ВЙВМЙПФЕЛЙ. чЕДШ ПОЙ РТЙЧСЪБОЩ Л ЛПОЛТЕФОПК ПРЕТБГЙПООПК УЙУФЕНЕ, Б НЩ РЙЫЕН ОПЧХА.

уВПТЛБ ПВТБЪБ ДЙУЛБ

пВПКДХУШ ВЕЪ МЙЫОЙИ ЛПННЕОФБТЙЕЧ Й РТПУФП РТЙЧЕДХ МЙОХЛУПЧЩК УЛТЙРФ УВПТЛЙ ПВТБЪБ:

Dd if=bin/boot.bios.bin of=bin/boot_sector.bin bs=512 count=1 dd if=bin/boot.bios.bin of=disk/boot.bin bs=1 skip=512 cp bin/kernel.bin disk/kernel.bin bin/make_listfs of=disk.img bs=512 size=2880 boot=bin/boot_sector.bin src=./disk

пО РТЕДРПМБЗБЕФ, ЮФП ЧУЕ УЛПНРЙМЙТПЧБООЩЕ ЖБКМЩ МЕЦБФ Ч bin Ч ФЕЛХЭЕН ЛБФБМПЗЕ, Б ЕЭЈ ЙНЕЕФУС ЛБФБМПЗ disk, Ч ЛПФПТПН МЕЦЙФ boot.cfg УМЕДХАЭЕЗП УПДЕТЦБОЙС:

# Loading kernel Lkernel.bin # Boot 32 bit kernel S32

еУМЙ ЧЩ ЧУЈ УДЕМБМЙ РТБЧЙМШОП, РПМХЮЕООЩК ПВТБЪ НПЦОП ЪБРХУФЙФШ Ч ЬНХМСФПТЕ ЙМЙ ДБЦЕ ОБ ТЕБМШОПН ЦЕМЕЪЕ Й ЧЩ РПМХЮЙФЕ РПДПВОХА ЛБТФЙОХ:

ъБЗТХЪЮЙЛ УЮЙФЩЧБЕФ ЛПОЖЙЗХТБГЙПООЩК ЖБКМ, ЪБЗТХЦБЕФ СДТП, РЕТЕИПДЙФ Ч ЪБЭЙЭЈООЩК ТЕЦЙН Й РЕТЕДБЈФ ЕНХ ХРТБЧМЕОЙЕ. рПМХЮЙЧ ЕЗП, ОБЫЕ СДТП ЧЩЧПДЙФ РПУМЕДОАА УФТПЛХ ОБ ЬЛТБО. ьФП МЙЫШ ОБЮБМП ДПМЗПЗП РХФЙ, НЩ РЕТЕИПДЙН Л УБНПК ЙОФЕТЕУОПК ЮБУФЙ ТБЪТБВПФЛЙ. фЕРЕТШ ЧЩРХУЛЙ ВХДХФ ЗПТБЪДП ВПМЕЕ РТПУФЩН ДМС ЧПУРТЙСФЙС, ВМБЗПДБТС ЙУРПМШЪПЧБОЙА СЪЩЛБ ЧЩУПЛПЗП ХТПЧОС, ЛПФПТЩК ЛБЛ С ОБДЕАУШ ЧУЕ Й ФБЛ ЪОБАФ. еУМЙ ЧЩ ОЕ ИПФЙФЕ ТБЪВЙТБФШУС У Assembler, НПЦЕФЕ РТПУФП ЧЪСФШ НПК ЗПФПЧЩК ЪБЗТХЪЮЙЛ Й startup.asm Й ЙЪНЕОСФШ ХЦЕ ФПМШЛП УПДЕТЦЙНПЕ main.c, РПУЛПМШЛХ ЧЕУШ ЛПД ДП ЬФПЗП ОЕ ДЙЛФХЕФ ЦЈУФЛП ЛБЛЙЕ-МЙВП РБТБНЕФТЩ СДТБ (ЛТПНЕ жу У ЛПФПТПК НЩ ЪБЗТХЦБЕНУС) Й РПЪЧПМСЕФ РПУФТПЙФШ ОБ УЧПЕК ВБЪЕ ЮФП ХЗПДОП.

бЧФПНБФЙЪБГЙС УВПТЛЙ ЙМЙ Makefile

чЩ НПЗМЙ ЪБНЕФЙФШ, ЮФП ЧТХЮОХА ОБВЙЧБФШ УФПМШЛП ЛПНБОД ДПУФБФПЮОП ХФПНЙФЕМШОП. л ФПНХ ЦЕ ОЕ ЧУЕЗДБ ЕУФШ ОЕПВИПДЙНПУФШ РЕТЕЛПНРЙМЙТПЧБФШ ЧУЕ ЖБКМЩ. оБРТЙНЕТ, ЕУМЙ startup.asm ОЕ ВЩМ ЙЪНЕОЈО, НПЦОП ОЕ ЧЩЪЩЧБФШ fasm. уРЕГЙБМШОП ДМС ХРТПЭЕОЙС ЛПНРЙМСГЙЙ РТЙМПЦЕОЙК ВЩМБ РТЙДХНБОБ ХФЙМЙФБ make, ЛПФПТБС ЧИПДЙФ Ч УФБОДБТФОХА РПУФБЧЛХ GCC Й MinGW.

мАВПК Makefile УФПЙФ ЙЪ ОБВПТБ РТБЧЙМ У ФБЛПК УФТХЛФХТПК:

ЙНСгЕМЙйМЙжБКМБ: йНСрЕТЧПЗПйУИПДОПЗПжБКМБ йНСчФПТПЗПйУИПДОПЗПжБКМБ... лПНБОДЩлПНРЙМСГЙЙ

рЕТЧПЕ РТБЧЙМП, ЛПФПТПЕ ДПМЦОП ВЩФШ Ч МАВПН Makefile - ГЕМШ all. make УНПФТЙФ ОБ ЪБЧЙУЙНПУФЙ ГЕМЙ all Й ЛПНРЙМЙТХЕФ ЙИ, Б ЪБФЕН ЧЩРПМОСЕФ ЛПНБОДЩ Й ЬФПК ГЕМЙ. дМС ЛБЦДПК ДТХЗПК ГЕМЙ УОБЮБМБ УПВЙТБАФУС ЕЈ ЪБЧЙУЙНПУФЙ. рТЙ ЬФПН ЙНС ГЕМЙ Й ЙНС ЪБЧЙУЙНПУФЕК НПЗХФ УПЧРБДБФШ У ЙНЕОБНЙ ТЕБМШОЩИ ЖБКМПЧ. ч ФБЛПН УМХЮБЕ РЕТЕУВПТЛБ ГЕМЙ РТПЙЪПКДЈФ ФПМШЛП ЕУМЙ ЙУИПДОЙЛЙ ВЩМЙ ЙЪНЕОЕОЩ.

еЭЈ ПДОБ ГЕМШ, ЛПФПТБС ЮБУФП ЙУРПМШЪХЕФУС Ч Makefile - clean. еЈ ЪБДБЮБ ХДБМЙФШ ЧУЕ ВЙОБТОЩЕ ЖБКМЩ, ЮФПВЩ ОБЮБФШ УВПТЛХ "У ЮЙУФПЗП МЙУФБ". чПФ ФБЛ НПЦЕФ ЧЩЗМСДЕФШ Makefile ДМС СДТБ:

All: startup.o main.o script.ld ld --oformat=binary -melf_i386 -T script.ld -o kernel.bin startup.o main.o startup.o: startup.i386.asm fasm startup.i386.asm startup.o main.o: main.c gcc -c -m32 -ffreestanding -o main.o main.c clean: rm -v *.o kernel.bin

ьФПФ ФЕЛУФ ОЕПВИПДЙНП УПИТБОЙФШ Ч ЖБКМ У ЙНЕОЕН Makefile (ВЕЪ ТБУЫЙТЕОЙС) Ч ЛБФБМПЗ У ЙУИПДОЩНЙ ФЕЛУФБНЙ СДТБ. фЕРЕТШ ДПУФБФПЮОП ЧЩРПМОЙФШ ЛПНБОДХ make ВЕЪ РБТБНЕФТПЧ, ОБИПДСУШ Ч ЬФПН ЛБФБМПЗЕ Й НЩ РПМХЮЙН ЖБКМ kernel.bin (МЙВП УППВЭЕОЙС ПВ ПЫЙВЛБИ, ЕУМЙ ЮФП-ФП РПЫМП ОЕ ФБЛ).

б ЧПФ ФБЛ С УПВЙТБА ЪБЗТХЪЮЙЛ:

All: boot.bios.bin boot.bios.bin: boot.bios.asm fasm boot.bios.asm boot.bios.bin clean: rm -v boot.bios.bin

Й make_listfs:

All: compile compile: make_listfs.c gcc -o make_listfs make_listfs.c clean: rm -f make_listfs make_listfs.exe

оХ Й ОБЛПОЕГ ТБУУЛБЦХ РТП ЧЩЪПЧ ДТХЗЙИ Makefile ЙЪ ПДОПЗП. с ДПУФБФПЮОП МЕОЙЧ, ЮФПВЩ ДБЦЕ ЪБИПДЙФШ Ч ЛБФБМПЗЙ У ЛБЦДЩН ЛПНРПОЕОФПН УЙУФЕНЩ, РПЬФПНХ УПЪДБМ 1 Makefile, ЛПФПТЩК УПВЙТБЕФ УТБЪХ ЧУА УЙУФЕНХ. х НЕОС ЕУФШ РБРЛБ src, Ч ОЕК РПДЛБФБМПЗЙ: boot, kernel, make_listfs. ч УБНПК src ОБИПДЙФУС ЧПФ ФБЛПК Makefile:

All: make -C boot/ make -C kernel/ make -C make_listfs/ clean: make -C boot/ clean make -C kernel/ clean make -C make_listfs clean

фЕРЕТШ, ОБИПДСУШ Ч ЛБФБМПЗЕ src С РТПУФП РЙЫХ make Й РПМХЮБА РПМОПУФША УПВТБООХА УЙУФЕНХ, Б ЕУМЙ ОБРЙУБФШ make clean, ФП ЧУЕ ДЧПЙЮОЩЕ ЖБКМЩ ВХДХФ ХДБМЕОЩ Й ПУФБОХФУС ФПМШЛП ЙУИПДОЙЛЙ.

оХ Й Ч ДПЧЕТЫЕОЙЕ РПУМЕДОЙК УЛТЙРФ, ЛПФПТЩК ЧЩРПМОСЕФ РПМОХА ЛПНРЙМСГЙА Й УВПТЛХ ЧУЕИ ЛПНРПОЕОФПЧ Й ПВТБЪБ ДЙУЛБ. ч ПДОПН ЛБФБМПЗЕ У ОЙН ОБДП ТБЪНЕУФЙФШ src, РХУФПК ЛБФБМПЗ bin Й ЛБФБМПЗ disk У ЖБКМПН boot.cfg.

#!/bin/sh make -C src cp src/boot/boot.bios.bin bin/ cp src/kernel/kernel.bin bin/ cp src/make_listfs/make_listfs bin/ dd if=bin/boot.bios.bin of=bin/boot_sector.bin bs=512 count=1 dd if=bin/boot.bios.bin of=disk/boot.bin bs=1 skip=512 cp bin/kernel.bin disk/kernel.bin bin/make_listfs of=disk.img bs=512 size=2880 boot=bin/boot_sector.bin src=./disk read -p "Press Enter to continue..." dummy

у ФБЛЙН ОБВПТПН УЛТЙРФПЧ УВПТЛБ УЙУФЕНБ УФБОПЧЙФУС РТЕДЕМШОП РТПУФПК, ПУПВЕООП ЕУМЙ ХЮЕУФШ, ЮФП РПУМЕДОЙК УЛТЙРФ НПЦОП ЪБРХУЛБФШ ДЧПКОЩН ЛМЙЛПН ЙЪ ЖБКМПЧПЗП НЕОЕДЦЕТБ. тБЪМЙЮОЩЕ ЛПНБОДЩ ЧТПДЕ dd, cp, rm ОЕ УХЭЕУФЧХАФ РПД Windows, РПЬФПНХ ЕЈ РПМШЪПЧБФЕМСН РТЙЗПДЙФУС РБЛЕФ MSYS ЙМЙ Cygwin. пДОБЛП РТПУФБС УВПТЛБ ЧУЕИ ЛПНРПОЕОФПЧ ВХДЕФ ТБВПФБФШ ДБЦЕ ЕУМЙ Х ЧБУ ЕУФШ ФПМШЛП GCC Й fasm (make_listfs МЕЗЛП УЛПНРЙМЙТХЕФУС Й ЪБРХУФЙФУС Ч ЧЙДЕ Windows-РТЙМПЦЕОЙС).

рТЙНЕЮБОЙЕ ДМС РПМШЪПЧБФЕМЕК пу Windows

ld ДМС Windows ОЕ УПЧУЕН РПМОПГЕООЩК - ПО ОЕ РПДДЕТЦЙЧБЕФ ЧЩЧПД УТБЪХ Ч ВЙОБТОЩК ЖБКМ, ФПМШЛП Ч EXE. йУРТБЧЙФШ ЬФП НПЦОП УПЪДБЧ УОБЮБМБ EXE (ld ОЕ ПВТБФЙФ ЧОЙНБОЙЕ, ЮФП ВБЪПЧЩЕ БДТЕУБ УЕЛГЙК ОЕЧПЪНПЦОЩЕ ДМС ЧЕОДПЧЩИ ВЙОБТОЙЛПЧ), Б РПФПН ЧЩФБЭЙФШ ПФФХДБ ЮЙУФЩЕ ДБООЩЕ У РПНПЭША objcopy. еУМЙ ЧЩ УФПМЛОЈФЕУШ У ФЕН, ЮФП ld ПФЛБЪЩЧБЕФУС УПЪДБЧБФШ ЖБКМ kernel.bin, ЧПУРПМШЪХКФЕУШ ЧПФ ФБЛЙН Makefile ДМС СДТБ:

All: startup.o main.o script.ld ld -melf_i386 -T script.ld -o kernel.bin startup.o main.o objcopy kernel.bin -O binary startup.o: startup.i386.asm fasm startup.i386.asm startup.o main.o: main.c gcc -c -m32 -ffreestanding -o main.o main.c clean: rm -v *.o kernel.bin

ъБПДОП ХВЕТЙФЕ УФТПЛХ OUTPUT_FORMAT("binary") ЙЪ script.ld. фЕРЕТШ Й РПД Windows РПМХЮЙФУС УПВТБФШ СДТП УЙУФЕНЩ.

ъБЗТХЪЛБ УЙУФЕНЩ ОБ ТЕБМШОПК НБЫЙОЕ

рПУМЕ ФБЛЙИ ХУРЕИПЧ Х ОЕЛПФПТЩИ НПЦЕФ ЧПЪОЙЛОХФШ ЦЕМБОЙЕ ПРТПВПЧБФШ ОПЧХА пу ОБ ТЕБМШОПН ЦЕМЕЪЕ. ьФП ОЕ РТЕДУФБЧМСЕФ РТПВМЕН. у РПНПЭША HxD Ч Windows ПФЛТПКФЕ ДЙУЛЕФХ ЙМЙ ЖМЕЫЛХ, ЧЩВТБЧ ЧБТЙБОФ "пФЛТЩФШ ДЙУЛ". рТЙ ПФЛТЩФЙЙ ЖМЕЫЛЙ ЧБЦОП ПФЛТЩФШ ЙНЕООП УБНХ ЖМЕЫЛХ, Б ОЕ ЕЈ ТБЪДЕМ. ч ДТХЗПК ЧЛМБДЛЕ ПФЛТПКФЕ disk.img, ЧЩДЕМЙФЕ ЕЗП УПДЕТЦЙНПЕ РПМОПУФША Й УЛПРЙТХКФЕ ОБ ДЙУЛ У ЕЗП УБНПЗП ОБЮБМБ. рПУМЕ ЬФПЗП НПЦОП ОБЦБФШ "уПИТБОЙФШ" Й ДПЦДБФШУС ПЛПОЮБОЙС ЪБРЙУЙ. чУЕ ДБООЩЕ ОБ ЖМЕЫЛЕ ЙМЙ ДЙУЛЕФЕ РТЙ ЬФПН ВХДХФ ХОЙЮФПЦЕОЩ, Б ДМС ФПЗП, ЮФПВЩ ЕЈ ЙУРПМШЪПЧБФШ УОПЧБ РП ОБЪОБЮЕОЙА, ЕЈ РТЙДЈФУС ЪБОПЧП ПФЖПТНБФЙТПЧБФШ!

рПМШЪПЧБФЕМЙ Linux НПЗХФ РПУФХРЙФШ РТПЭЕ - ЧЩРПМОЙФШ УРЕГЙБМШОХА ЛПНБОДХ Ч ФЕТНЙОБМЕ. дМС ДЙУЛЕФЩ:

Dd if=disk.img of=/dev/fd0

дМС ЖМЕЫЛЙ:

Dd if=disk.img of=/dev/sdX

чНЕУФП sdX ОБДП РПДУФБЧЙФШ ОБУФПСЭЕЕ ЙНС ХУФТПКУФЧБ (sda, sdb, sdc, sdd Й Ф. Д.). зМБЧОПЕ РТЙ ЬФПН ОЕ РЕТЕРХФБФШ Й ОЕ ЪБРЙУБФШ ПВТБЪ ОБ УЙУФЕНОЩК ДЙУЛ, ХОЙЮФПЦЙЧ ЧУЕ ДБООЩЕ. тБЪХНЕЕФУС, ПВЕ ЛПНБОДЩ ДПМЦОЩ ЧЩРПМОСФШУС ПФ ЙНЕОЙ root ЙМЙ У РПНПЭША sudo.

рПУМЕ ЬФПЗП ОБДП ОБУФТПЙФШ Ч BIOS ЪБЗТХЪЛХ У ДЙУЛЕФЩ ЙМЙ ЖМЕЫЛЙ (УФБТЩЕ BIOS ОЕ РПДДЕТЦЙЧБАФ ЖМЕЫЛЙ) Й ОБУМБЦДБФШУС ЧЙДПН "Hello world".

ъБЛМАЮЕОЙЕ

оХ ЧПФ УПВУФЧЕООП Й ЧУЈ ОБ УЕЗПДОС. нЩ ОБЛПОЕГ-ФП ЪБЛПОЮЙМЙ РТПЗТБННЙТПЧБОЙЕ ОБ Assembler (ИПФС Ч у ЧУЈ ТБЧОП РТЙДЈФУС ЙОПЗДБ ДЕМБФШ БУУЕНВМЕТОЩЕ ЧУФБЧЛЙ ДМС ТБВПФЩ У ПВПТХДПЧБОЙЕН) Й РЕТЕЫМЙ ОБ СЪЩЛ ЧЩУПЛПЗП ХТПЧОС. еЭЈ ПЮЕОШ НОПЗП РТЕДУФПЙФ УДЕМБФШ. нЩ НПЦЕФЕ ХЦЕ РТПЧПДЙФШ ТБЪМЙЮОЩЕ ЬЛУРЕТЙНЕОФЩ, ЙЪНЕОСС НПК main.c, ФПМШЛП ХЮФЙФЕ, ЮФП МАВБС ПЫЙВЛБ (ДПУФХР Л ОЕУРТПЕГЙТПЧБООПК РБНСФЙ, ДЕМЕОЙЕ ОБ ОПМШ) РТЙЧЕДЈФ Л РЕТЕЪБЗТХЪЛЕ ЙМЙ ЪБЧЙУБОЙА УЙУФЕНЩ (НЩ РПЛБ ОЕ ПВТБВБФЩЧБЕН ЙУЛМАЮЕОЙС, РПЬФПНХ РТПГЕУУПТ ОЕ НПЦЕФ РТПДПМЦЙФШ ТБВПФХ РПУМЕ ПЫЙВЛЙ). дП ЧУФТЕЮЙ!

мАВЩЕ ЧПРТПУЩ ЧЩ НПЦЕФЕ ЪБДБФШ ОБ НПК БДТЕУ: [email protected] . й ДБ, УЕКЮБУ УБНПЕ ЧТЕНС ДМС ТБЪМЙЮОЩИ ЙДЕК РП ЛПОГЕРГЙЙ пу Й РТЕДМПЦЕОЙК.

Аббревиатура "NT" маркетингом расшифровывается как "New Technologies", но в проектной документации, она означала совсем другое. Дело в том, что Windows NT разрабатывалась для нового, еще не выпущенного в 1988-м году, процессора Intel i860. Его кодовое название было "N10" (N T en).

Первая версия - Windows NT 3.1, вышла через 5 лет, в 1993 году. На этот момент в команде было уже 250 разработчиков.

Windows сегодня

  • 1 миллиард пользователей
  • 140 миллионов строк кода (включая тестовый код и инструментарий)
    Код Windows очень разный. Какие-то части написаны 20 лет назад, какие-то появились только в текущей версии. Например, код Web Services on Devices (WSD) в Windows Vista существует в своей первой версии, код GDI находится на завершающей стадии своего развития и почти не изменяется, код DirectX уже хорошо разработан, но активно изменяется и в настоящее время.
  • 8000 разработчиков
  • 36 языков локализации
  • 20 лет разработки

Разработка Windows

20-30 лет назад использовалась только одна методология программирования "Водопад". Она представляет собой последовательность:

Спецификации → Дизайн → Реализация → Тестирование → Поставка.

Но такая методология работает только для небольших проектов. Для такого продукта, как Windows сегодня, нужны другие методологии:

  • Product Cycle Model
  • Team Software Process
  • "Экстремальное программирование"

У всех этих методологий есть и преимущества и недостатки. В зависимости от размера команды и этапа развития компонента разные группы разработчиков Windows применяют разные методологии разработки.
Для Windows, как продукта в целом, используется Product Cycle Model:

  • Периоды по 3-4 месяца
  • Внутри периода - "водопад"

Самая главная проблема в разработке продукта такого масштаба состоит в том, что разработка требует времени. На начальном этапе решаются те проблемы, которые существуют в текущем времени и существующими средствами. Но единственная вещь, которая постоянна, это то, что все изменится. За годы разработки:

  • Требования изменятся
  • Возможности изменятся
  • График работ изменится
  • Проект изменится
  • Пользователи изменятся

Несмотря на то, что разные команды ведут разработку по-разному, существуют "универсальные" правила:

  • Выпуск промежуточных версий (milestones, beta, CTP) для широких масс тестеров
  • Выпуск внутренних сборок с короткими циклами (1 сутки)
  • Простота и надежность дизайна
  • Личные и командные вычитывания кода
  • Unit-тесты
  • Верификационные тесты (Build Verification Tests)
  • Любая промежуточная сборка должна быть качественной (то, что написано, должно работать)

От себя отмечу, что за месяц работы с Windows 7 build 6801 в качестве основной ОС на домашнем компьютере, у меня сформировалось положительное впечатление об этой сборки.

Весь процесс разработки Windows построен вокруг ежедневной сборки:

  • Это пульс продукта
  • Разработка никогда не прекращается
  • Ежедневное автоматическое тестирование
  • Интеграция на ранней стадии
  • Ответственность разработчиков
  • Очевидное состояние продукта

Когда-то раньше была только одна ветка исходного кода, и все разработчики вносили изменения прямо в неё. Сейчас команда разработчиков настолько большая, что это не работает. Поддерживается множество веток, среди которых есть основная - WinMain. У каждой лаборатории есть своя локальная ветка разработки, в которую интегрируются изменения. Проверенные изменения со временем интегрируются в WinMain.

Ежедневный цикл разработки:

  • 15:00 - Допущенные к интеграции изменения в систему контроля исходного кода
  • Сборка 6 версий (Free/Checked - x86, x64, IA64)
  • 18:00 - Новые версии доступны для тестирования
  • Новая версия устанавливается на несколько тысяч рабочих станций и серверов для тестирования
  • Автоматизированный стресс-тест
  • 05:00 - Протоколы тестов анализируются, сбои диагностируются
  • 09:00 - Сводные отчеты автоматически рассылаются командам
  • 09:30 - Сводное совещание руководителей команд для определения целей

Все участники проекта, включая самых высокопоставленных руководителей, используют промежуточные версии на своих рабочих (а обычно и домашних) компьютерах.

На чем пишется Windows?

  • C, C++, C#, Ассемблер (x86, x64, IA64)
    Ассемблеры применяются в довольно ограниченном объеме в тех ситуациях, когда без этого не обойтись
  • Visual Studio, Source Insight, build, nmake
  • Source Depot - система контроля исходных текстов
  • WinDbg, KD, NTSD - отладчики

Многие внутренние инструменты, такие как build, можно скачать с microsoft.com/whdc/devtools.

Изменения ядра Windows 7

Ядро Windows 7 претерпело следующие изменения:

  • Рефакторинг
    Почему в Windows нельзя удалить графическую подсистему?
    Ответ на этот вопрос с технической точки зрения состоит в том, что графическая подсистема в Windows не самостоятельна, это часть подсистемы Win32.
    В Windows 7 произошел рефакторинг многих низкоуровневых компонентов для того, чтобы разбить зависимости. Пользователям это не будет заметно, появятся только новые Dll, например kernel32.dll разделилась на kernel32.dll и kernelbase.dll.
    Это разбиение дало возможность выделить минимальное ядро, называемое MinWin (20 мегабайт на диске).
  • Поддержка EFI для x86 и x64 (как в Vista SP1)
    Многие производители пытаются избавиться от BIOS в пользу EFI.
  • Загрузка с VHD (виртуальный жесткий диск)
  • Параллельная инициализация устройств и старт сервисов
    При загрузке Windows довольно длительное время занимает построение дерева устройств. PNP-менеджер должен опрашивать драйверы шин (PCI, USB, FireWire и др.) на предмет того, какие устройства на них есть. И большую часть времени процессор ждет, пока устройства ответят (или нет). Ведь для того, чтобы определить устройства на шине нужно их опросить. Если они есть, то они ответят, а если нет, то приходится ждать, и процессор простаивает. Параллельное выполнение этих задач сокращает время загрузки.
  • Удаление Dispatcher lock из планировщика и PFN lock из менеджера памяти
    Последние несколько лет тактовые частоты процессоров не растут, и развитие идет в сторону увеличения кол-ва параллельно выполняющихся инструкций как на уровне одного ядра, так и на уровне системы (multicore). В связи с этим, была проведена большая работа по улучшению масштабирования.
    Два самых "горячих" лока, которые были в ядре, это Dispatcher lock и PFN lock были удалены.
    Dispatcher lock использовался планировщиком при изменении состояния потоков. Этот лок был удален, и состояние потока "ожидание" разделилось на несколько:
    • Ожидание: В процессе
    • Ожидание: Завершено
    • Ожидание: Отменено
    PFN lock использовался при изменении атрибутов физических страниц памяти. В мультипроцессорной системе каждый процессор запрашивал доступ к этому локу, что вело к большим затратам времени.
  • Поддержка 256 логических процессоров
    Раньше в Windows в качестве affinity mask использовалось машинное слово. Это было сделано из-за того, что так было легко находить свободные процессоры - каждый бит представляет собой процессор. Соответственно, в 32-битной системе поддерживалось 32 логических процессора, а в 64-битной - 64.
    В Windows 7 в результате перехода на сегментную модель affinity mask стала возможна поддержка 256 логических процессоров. Процессоры стали группироваться в группы/сегменты. В каждой группе могут находиться до 64-х процессоров. В результате получается обратная совместимость, старые программы "видят" только процессоры в одной группе, а новые программы, использующие новые интерфейсы, работают со всеми процессорами в системе.
  • Улучшенное энергосбережение: отключение процессорных сокетовСегодня стоит серьезная проблема энергосбережения не только перед владельцами ноутбуков, но и владельцами датацентров. В США 2% электроэнергии потребляются компьютерными датацентрами. Многие из них выключают часть своих серверов на время низкой активности пользователей (выходные дни).
    Было выяснено, что гораздо выгоднее отключать весь процессорный сокет, чем по одному ядру на нескольких, т.к. в этом случае можно отключить и всю инфраструктуру поддержки сокета (контроллер памяти).

Сопровождение Windows, обновления

Раньше обновления зачастую были кумулятивными(накапливаемыми). Это означало, что если ошибочный код содержался в раннем обновлении компонента, то и поздние версии будут содержать этот код. Но не всем пользователям нужны все обновления, у них разная конфигурация.

Теперь после выпуска (RTM) в Windows существует 2 версии исходного кода:

  • RTM GDR (General Distribution Release)
    Включает те немногие изменения, которые предназначены для всех. В основном исправления безопасности.
  • RTM LDR (Limited Distribution Release)
    Во время установки обновления клиент Windows Update выбирает нужную ему ветку и устанавливает код из нее.

Создание обновления безопасности

Работа по созданию обновления безопасности начинается с обнаружения уязвимости. Есть масса разных способов обнаружения - внутренние команды безопасности, партнеры безопасности, разработчики. Когда уязвимость обнаружена, начинается 2 параллельных процесса:

  • Разработка исправления для всех платформ
  • Поиск "вариантов"
    Масштабный поиск похожих вариантов уязвимостей на всех платформах. Поиск не идентичного кода, а похожего.

После разработки исправления, начинаются проверки его кода. Когда они завершатся, исправление интегрируется в сборку, и сборка отправляется на тестирование:

  • Ручное и автоматическое тестирование компонент
  • Автоматическое тестирование искажений форматов файлов, сетевых компонент и т.п. (больше миллиона вариантов)
  • Тестирование системы в целом, включая тестирование обратной совместимости

Только исправления, удовлетворяющие всем критериям качества, допускаются к выпуску на Windows Update и Download Center.

  • Вперёд >