|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
|
Пишем загрузочный сектор12.10.2013, 07:37. Показов 50932. Ответов 14
Метки нет (Все метки)
Статья Пишем свой загрузочный сектор без указания автора найдена в разделе assembler на сайте http://www.cyberguru.ru. Пятиминутный поиск в Google привел на сайт автора этой статьи Алексея Золотова www.zolotov.h14.ru, у которого оказался целый цикл статей, которые, как пишет автор могут быть полезными тем, кто хочет написать свою ОС (К сожалению, проект заморожен на неопределенное время.)
Многозадачная ОС
10
|
|
| 12.10.2013, 07:37 | |
|
Ответы с готовыми решениями:
14
Загрузочный сектор [NASM] Загрузочный сектор
|
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 12.10.2013, 07:46 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
статья взята на домашней страничке Алексея Золотова http://zolotov.h14.ru/doc/os/os.php
О проекте Я давно хотел написать свою маленькую операционную систему. Мечтать невредно, но пора бы начать осуществлять свою мечту. В этом первом разделе я попытаюсь описывать этот процесс с подробными комментариями, чтобы любой желающий мог присоединиться. Конечно, можно взять исходники какой-нибудь Unix-подобной операционной системы и переделывать их на свой лад, но я намерен писать с нуля новую, свою операционную систему.Процесс загрузки компьютера начинается с небольшой программы POST зашитой BIOS, его мы естественно менять не будем и начнем, как все нормальные люди, с загрузочного сектора. Так как мы с начала будем писать загрузочный сектор для трех дюймовой дискеты с файловой системой FAT, то советую прочитать немного про FAT. Список сайтов Здесь я буду приводить список ссылок на другие сайты подобной тематики, чтобы вам (и мне тоже) было проще найти нужную информацию. Если вы желаете добавить ссылку, напишите мне на e-mail zolotov-alex@mail.ru и если я сочту необходимым, то я добавлю сюда вашу ссылку.
______________________________________ статья взята на домашней страничке Алексея Золотова http://zolotov.h14.ru/doc/os/post.phpНачальная загрузка Начнем с самого начала – аппаратного сброса процессора. При поступлении сигнала Reset процессор перестает исполнять инструкции и управлять системной шиной. В этот момент процессор пассивен, он принимает на свои входы сигналы, задающие его конфигурацию (коэффициент умножения, роль в много процессорных системах и некоторые другие параметры), регистры процессора (не все) приводятся в определенное состояние. После окончания сигнала Reset процессор исполняет первую инструкцию, расположенную по определенному адресу: на 15 байт меньше максимального физического адреса (у процессоров P6 возможен выбор между значением 0xFFFFFFF0 и 0xFFFF0). По этому адресу должна располагаться инструкция, с которой начинается инициализация процессора. Программа начальной инициализации, называемая POST (Power On Self Test – самотестирование по включению), хранится в постоянной памяти ROM BIOS (ПЗУ базовой системы ввода/вывода). Она выполняет инициализацию процессора – устанавливает необходимый режим и значения регистров. Далее выполняется проверка работоспособности и инициализации подсистем компьютера. После всех проверок и инициализации BIOS знает реальную конфигурацию компьютера и готова к загрузке операционной системы. Программа POST завершается вызовом процедуры начальной загрузки.Процедура начальной загрузки (bootstrap loader) вызывается как программное прерывание (BIOS Int 19h). Эта процедура определяет первое готовое устройство из списка разрешенных и доступных (гибкий или жесткий диск, компакт-диск, сетевой адаптер) и пытается загрузить с него короткую программу загрузки. Эта программа может выполнятся в два этапа: сначала с жесткого диска загружается загрузчик MBR (Master Boot Record – главная загрузочная запись) и ему передается управление. Затем MBR определяет активный раздел и загружает с него загрузчик этого раздела и передает ему управление. В свою очередь загрузчик раздела загружает необходимые файлы операционной системы и передает ей управление. Загрузчик загружается по физическому адресу 0x7C00 размером 512 байт. Процессор при этом находится в реальном режиме адресов и доступны системные вызовы BIOS. Загрузчик в виду его маленького размера должен найти на диске и загрузить в память другой код, который собственно и выполнит загрузку и инициализацию операционной системы. Список литературы
______________________________________ статья взята на домашней страничке Алексея Золотова http://zolotov.h14.ru/doc/os/fat.phpФайловая система FAT FAT (File Allocation Table – таблица размещения файлов) - этот термин относится к одному из способов организации файловой системы на диске. Эта таблица хранит информацию о файлах на жестком диске в виде последовательности чисел, определяющих, где находится каждая часть каждого файла. С ее помощью операционная система выясняет, какие кластеры занимает нужный файл. FAT - является самой распространенной файловой системой и поддерживается подавляющим большинством операционных систем. Сначала FAT была 12-разрядной и позволяла работать с дискетами и логическими дисками объемом не более 16 Мбайт. В MS-DOS версии 3.0 таблица FAT стала 16-разрядной для поддержки дисков большей емкости, а для дисков объемом до 2 047 Гбайт используется 32-разрядная таблица FAT.Заголовок файловой системы FAT Эта часть загрузочного сектора известна как BIOS Parameter Block (BPB) (блок параметров BIOS). Она содержит физические характеристики диска, которые MS-DOS и Windows используют при поиске определенного участка. Складывая или перемножая значения этих параметров, операционная система узнает, где находится таблица FAT, корневой каталог, где начинается и кончается область данных.Общая часть заголовка файловой системы FAT Эта часть общая для всех файловых систем семейства FAT (FAT12, FAT16 и FAT32):
FAT12 и FAT16 FAT12 и FAT16 имеют одинаковый формат заголовка.
Загрузочный сектор И так, приступим. Как я уже говорил, в начале нашего загрузочного сектора располагается заголовок FAT, опишем его:
По инструкции jmp short BootStart мы переходим на наш код. Проведем небольшую инициализацию:
Теперь нам нужно вычислить номера первых секторов корневого каталога и данных файлов.
Если файл найден, то загрузим его в память и передадим управление на его начало.
Теперь разберем процедуру загрузки секторов. Процедура получает номер сектора в dx:ax (нумерация с нуля) и преобразует его к формату CSH (цилиндр, сектор, сторона), используемому прерыванием BIOS int 0x13.
> nasm -f bin boot.asm -lboot.lst -oboot.bin Осталось только как-то записать этот образ в загрузочный сектор вашей дискеты и разместить в корне этой дискеты файл загрузчика BOOTOR. Загрузочный сектор можно записать с помощью такой вот простой программы на Turbo (Borland) Pascal. Эта программа будет работать как в DOS, так и в Windows - пробовал на WinXP - работает как ни странно, но только с floopy. Но все же я рекомендую запускать эту утилиту из-под чистого DOS'а, т.к. WinXP обновляет не все поля в заголовке FAT и загрузочный сектор может работать некорректно.
5
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
||||||
| 12.10.2013, 09:58 [ТС] | ||||||
|
статья взята на домашней страничке Алексея Золотова http://zolotov.h14.ru/doc/os/bootor.php
Загрузчик ядра Относительно процесса загрузки, ядро операционной системы состоит из двух частей 16-битной и 32-битной. Ядро получает управление в реальном режиме, проводит первичную инициализацию 32-битной части, переходит в защищенный режим и основная часть инициализации ядра происходит в защищенном режиме. В этой статье мы рассмотрим 16-битную часть - загрузчик ядра.Пока наше ядро имеет небольшие размеры мы для простоты включим файл 32-битной части (далее просто ядро) в 16-битную часть (далее загрузчик ядра). Основные задачи загрузчика ядра:
3
|
||||||
|
1127 / 261 / 9
Регистрация: 11.06.2010
Сообщений: 1,049
|
||||||
| 12.10.2013, 11:37 | ||||||
|
статья взята на домашней страничке Алексея Золотова http://www.zolotov.h14.ru/doc/os/get_mem.php
Определение размера физической памяти В этой статье мы рассмотрим, как узнать размер физической памяти.Функции BIOS Все функции с случае ошибки устанавливают флаг CF.int 12h Выход:
int 15h функция 88h Вход:
int 15h функция 0E801h Вход:
int 15h функция 0E820h Вход:
Формат структуры:
4
|
||||||
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
||||||
| 12.10.2013, 12:30 [ТС] | ||||||
|
Взято здесь http://www.desy.de/~tigrank/rusfaq.html#boot
Как произвести запись в BOOT-сектор Ниже следует программа, которая записывает в BOOT-сектор часть своего тела, как отдельную программу. Только надо учесть, что не всякую программу можно туда положить. Недоступность прерываний (за редким исключением) – только одна из проблем, следует учитывать размер записи (не более 512 байт) и так далее. А вообще, если хотите поработать с BOOT-сектором, было бы неплохо учиться этому на основе изучения вирусов.
3
|
||||||
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 12.10.2013, 13:30 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Раз пошла такая пьянка, то до кучи и статья Крис Касперски ака мыщъх (взято отсюда http://www.insidepro.com/kk/065/065r.shtml)
MBR своими руками Сегодня мы напишем свой менеджер мультизагрузки. Это такая штука, что сидит в загрузочном секторе и грузит любую из нескольких установленных операционных систем по нашему выбору. Статья познакомит нас с прерыванием INT 13h, таблицей разделов и кое-чем еще. Введение Стандартный загрузчик, устанавливаемый большинством осей по умолчанию, слишком примитивен, чтобы его воспринимать всерьез, а нестандартные загрузчики от независимых разработчиков обычно слишком неповоротливы, монструозны и ненадежны. Вот и давайте напишем свой! Пока мы будет его писать, мы познаем дао и дзен ассемблера, научимся отлаживать программы без отладчика, и попробуем низкоуровневое железо винчестера на вкус.Начальная теоретическая подготовка Загрузка системы начинается с того, что BIOS считывает первый сектор жесткого диска, размещает его в памяти по адресу 0000:7С00h и передает сюда управление. Программисты называют его Главным Загрузочным Сектором (Master Boot Record), или, сокращенно, MBR. В начале MBR расположен машинный код загрузчика, за ним идет Таблица Разделов (Partition Table), описывающая схему разбиения логических дисков. В конце загрузочного сектора находится сигнатура 55h AAh, говорящая BIOS'у о том, что это действительно MBR, а не что-то еще.Загрузчик должен проанализировать Таблицу Разделов, найти предпочтительный логический диск, считать его первый сектор (он называется загрузочным - boot) и передать ему бразды правления. Вот минимум требований, предъявляемых к стандартному загрузчику, главный недостаток которого заключается в том, что на каждом логическом диске может быть установлена только одна операционная система, причем она должна быть установлена непременно на Primary Master'е, в противном случае загрузчик ее просто "не увидит" и нам придется менять порядок загрузки в BIOS Setup, а это слишком хлопотно и утомительно. Наш загрузчик будет свободен от всех этих глупых ограничений, но прежде чем зарываться вглубь, окинем MBR беглым взглядом. Воспользовавшись любым редактором диска (например, Microsoft Disk Probe из комплекта Resource Kit, прилагаемого к лицензионной Windows), считаем первый сектор физического диска. Он должен выглядеть приблизительно так: Рисунок 1. Внешний вид MBR - очень похоже на Матрицу, не правда ли? Первые 1BBh байт занимают код и данные загрузчика, среди которых отчетливо выделяются текстовые строки (кстати говоря, русифицировав сообщения загрузчика, Microsoft допустила грубейшую стратегическую ошибку, ведь никакого кириллического шрифта в BIOS'е нет и русские символы выглядят бессмысленной абракадаброй). По смещению 1BBh расположен четырехбайтовый идентификатор диска, принудительно назначаемый Windows при запуске Disk Manager'а. Коварство Microsoft не знает границ! Еще со времен первых IBM PC (тогда они назывались XT), загрузчик владел первыми 1BEh байтами MBR-сектора, и достаточно многие загрузчики (и вирусы!) использовали эти байты на всю катушку. Нетрудно сообразить, что произойдет, если внутрь загрузчика вдруг запишется идентификатор. Это убьет его! Поэтому, байты 1BBh - 1BEh лучше не трогать. Со смещения 1BEh начинается Таблица Разделов, представляющая собой массив из четырех записей типа partition. Каждая partition описывает свой логический диск, что позволяет нам создавать до четырех разделов на каждом HDD. Динамические диски, впервые появившиеся в W2K, хранятся в Базе Менеджера Логических Дисков (Logical Disk Manager Database) и в таблице разделов присутствовать не обязаны. В общем, устройство Главного Загрузочного Сектора выглядит так:
Таблица Разделов - это святая святых операционной системы. Каждая запись partition состоит из: адресов начала и конца раздела, типа раздела (NTFS, FAT16, FAT32...), количество секторов в разделе и флага "загруженности" раздела. Все адреса задаются либо CHS (Cylinder-Head-Sector - Цилиндр-Головка-Сектор), либо LBA (Logical Block Address - Логический Адрес Блока) формате. Конкретный формат определяется типом раздела (Boot ID), записанным в 04h байте. Количество существующих типов огромно и было бы слишком утомительно перечислять их здесь. В таблице 3 приведены лишь самые популярные из них. В CHS-формате, 01h и 05h байты partition'а хранят номер первой и последней головки раздела (см. таблицу 2). Байты 02h и 06h хранят 5 младших бит начального/конечного сектора и по два старших бита номера цилиндра, а оставшиеся биты лежат в следующем байте. Получается довольно запутанная схема, да к тому же адресующая только первые 8 Гбайт дискового пространства (CHS адрес занимает три байта или 24 бита, что при длине сектора в 512 байт дает 512 * 224 = 8.388.608 байт). Ха! Да жесткие диски преодолели этот барьер еще в прошлом веке! Это было достигнуто за счет введения LBA-адресации, последовательно нумерующей все сектора от 0 до многодетной матери. Начало раздела хранится в 32-битном поле relative offset (относительное смещение), содержащим смещение первого сектора раздела от начала partition или, попросту говоря, расстояние между концом partition и началом раздела. Конец раздела в явном нигде не хранится, вместо этого в специальном 32-битном поле partition size записывается количество секторов в разделе. Как нетрудно подсчитать, предельно допустимый размер одного раздела составляет (512 * 232 = 2.199.023.255.552 байт или 2.048 Гбайт), а совокупный объем всего диска вообще неограничен! Так что, для сегодняшних нужд LBA-адресации вполне достаточно, а там уж мы что-нибудь придумаем.
Рисунок 2. Основная Таблица Разделов, разбивающая винчестер на четыре логических диска. Четыре раздела partition обслуживают до четырех логических дисков, а больше уже никак. На большее в MBR-секторе просто не хватает места! Но ведь хорошо известно, что FDISK может разбивать винчестер хоть на 26 разделов. Как же ему это удается? А вот как! Помимо Основной Таблицы Разделом, хранящейся в MBR, мы можем создавать любое количество Расширенных Таблиц Разделов (Extended Partition Table), разбросанных по всему диску (см. рис. 3): Рисунок 3. Несколько Расширенных Таблиц Разделов, объединенных в одну цепочку, и разбивающих винчестер на любое количество логических дисков. Если partition имеет тип 05h или 0Fh, то она указывает совсем не на начало раздела, а на следующий MBR. Точнее, не совсем MBR, но нечто очень на него похожее. В нем присутствует полноценная Таблица Разделов с четырьмя входами: partition 1, partition 2, partition 3 и partition 4, каждая из которых указывает либо на логический диск, либо на новый MBR. Длина такой цепочки практически неограниченна и может превышать 26. Однако назначить буквы всем последующим разделам уже не удаться и под Windows 9x они будут просто не видны. Windows NT поддерживает гибридный механизм наименования разделов - по буквам и по именам, поэтому ей эти ограничения не страшны. Стандартный загрузчик позволяет запускать системы только из Основной Таблицы Разделов. Цепочку MBR'ов он не анализирует. В своем загрузчике мы исправим этот недостаток. Рисунок 4. Структурная схема типичной Расширенной Таблицы Разделов. Интерфейс INT 13h Управлять дисками можно как через порты ввода/вывода, так и через BIOS. Порты намного более могущественны и интересны, однако BIOS программируется намного проще, к тому же она поддерживает большое количество разнокалиберных накопителей, абстрагируя нас от конструктивных особенностей каждой конкретной модели. Поэтому мы будем действовать через нее, а точнее через интерфейс прерывания INT 13h. Попробуем прочитать сектор с диска в CHS-mode. Естественно, действовать нужно из самого MBR или из "голой" MS-DOS, иначе у нас ничего не получится, ведь Windows NT блокирует прямой доступ к диску даже из режима "Эмуляции MS-DOS"! Номер функции заносится в регистр AH. В случае чтения он равен двум. Регистр AL отвечает за количество обрабатываемых секторов. Поскольку мы собираемся читать по одному сектору за раз, занесем сюда единицу. Регистр DH хранит номер головки, а DL - номер привода (80h - первый жесткий диск, 81h - второй и так далее). Пять младших битов регистра CL задают номер сектора, оставшиеся биты регистра CL и восемь битов регистра CH определяют номер цилиндра, который мы хотим прочитать. Регистровая пара ES:BX указывает на адрес буфера-приемника. Вот, собственно говоря, и все. После выполнения команды INT 13h считываемые данные окажутся в буфере, а если произойдет ошибка (например, головка споткнется о BAD-сектор) BIOS установит флаг переноса (carry flag) и мы будем вынуждены либо повторить попытку, либо вывести грустное сообщение на экран. На ассемблерном языке это звучит так:
Листинг 1. Код, считывающий загрузочный сектор или Расширенную Таблицу Разделов. Запись сектора в CHS-режиме происходит практически точно также, только регистр AH равен не 02h, а 03h. С LBA-режимом разобраться намного сложнее, но мы, как настоящие хакеры, его обязательно осилим. Вот только пива хлебнем.Чтение сектора осуществляется функцией 42h (AH = 42h). В регистр DL, как и прежде, заносится номер привода, а вот регистровая пара DS:SI указывает на адресный пакет (disk address packet), представляющий собой продвинутую структуру следующего формата:
Код, читающий сектор в LBA-режиме, в общем случае выглядит так:
Листинг 2. Чтение сектора с диска в LBA-режиме. Запись осуществляется аналогично, только регистр AH содержит не 42h, а 43h. Регистр AL определяет режим: если бит 0 равен 1, BIOS выполняет не запись, а ее эмуляцию. Бит 2, будучи взведенным, задействует запись с проверкой. Если AL равен 0, выполняется обыкновенная запись по умолчанию.Теперь, освоившись с дисковыми прерываниями, перейдем к обсуждению остальных аспектов программирования. Как программируют загрузчики Лучше всего загрузчики программируются на FASM. С точки зрения ассемблера загрузчик представляет собой обыкновенный двоичный файл, предельно допустимый объем которого составляет 1BBh (443) байт. Немного? Но не будет спешить с выводами. Всякий раздел всегда начинается с начала цилиндра, а это значит, что между концом MBR и началом раздела имеется, по меньшей мере, sector per track свободных секторов. Практически все современные винчестеры имеют по 64 секторов в треке, что дает нам: 443 + 63 * 512 = 32.699 байт или ~32 Кбайт. Да в этот объем даже графический интерфейс с мышью и голой красавицей на обоях уместить можно. Но мы не будем! Настоящие хакеры работают в текстовом режиме с командной строкой, а красавиц лучше иметь, чем смотреть.Как уже говорилось, BIOS загружает MBR по адресу 7C00h, поэтому в начале ассемблерного кода должна стоять директива ORG 7C00h, а еще USE16 - ведь загрузчик выполняется в 16-разрядном реальном режиме. Позже, при желании он может перейти в защищенный режим, но это будет уже потом. Не будет лезть в такие дебри. Обнаружив загрузочный раздел (а обнаружить это можно по флагу 80h, находящемуся по смещению от начала partition), загрузчик должен считать первый сектор этого раздела, разместив его в памяти по адресу 0000:7C000h, то есть аккурат поверх своего тела. А вот это уже нехорошо! И чтобы не вызвать крах системы, загрузчик должен заблаговременно перенести свою тушу в другое место, что обычно осуществляется командой MOVSB. Копироваться можно в любое место памяти - от 0080:0067h до 9FE00h. Память, расположенную ниже 0080:0067h лучше не трогать, т.к. здесь находятся вектора прерываний и системные переменные BIOS'а, а от A000h и выше начинается область отображения ПЗУ, так что предельно доступный адрес равен A000h - 200h (размер сектора) = 9FE00h. Что еще? Ах да! Трогать DL-регистр ни в коем случае нельзя, поскольку в нем передается номер загрузочного привода. Некоторые загрузчики содержат ошибку, всегда загружаясь с первого жесткого диска. Стыдно не знать, что BIOS уже лет десять как позволяют менять порядок загрузки и потому загрузочным может быть любой привод. Кстати говоря, FASM - единственный известный мне ассемблер, "переваривающий" команду дальнего вызова JMP 0000:7C000h напрямую. Все остальные ассемблеры заставляют извращаться приблизительно так: PUSH offset_of_target/PUSH segment_of_target/RETF. Здесь мы заталкиваем в стек сегмент и смещение целевого адреса и выполняем далекий RETF, переносящий нас на нужное место. Еще можно воспользоваться самомодифицирующимся кодом, собрав команду JMP FAR "вручную" или просто расположить целевой адрес в одном сегменте с исходным адресом (например, 0000:7C000h -> 0000:7E000h), но это все муторно и утомительно. В общем, скелет нашего загрузчика будет выглядеть так:
Листинг 3. Скелет простейшего загрузчика на FASM'е. Инсталляция нашего загрузчика в MBR Под старушкой MS-DOS записать свой загрузчик в MBR было просто - достаточно дернуть прерывание INT 13h, функцию 03h (запись сектора). Но под Windows NT этот прием уже не работает и приходится прибегать к услугам функции CreateFile. Если вместо имени открываемого фала указать название устройства, например, "\\.\PHYSICALDRIVE0" (первый физический диск), мы сможем свободно читать и записывать его сектора вызовами ReadFile и WriteFile, соответственно. При этом флаг dwCreationDisposition должен быть установлен в значение OPEN_EXISTING, а dwShareMode - в значение FILE_SHARE_WRITE. Еще потребуются права root'а или в терминологии Windows - администратора, иначе ничего не получится. Законченный пример вызова CreateFile выглядит так:
Листинг 4. Открытие непосредственного доступа к жесткому диску под Windows NT. Открыв физический диск и убедившись в успешности этой операции, мы должны прочитать оригинальный MBR-сектор в буфер, перезаписать первые 1BBh байт, ни в коем случае не трогая Таблицу Разделов и сигнатуру 55h AAh (мы ведь не хотим, чтобы диск перестал загружаться, верно?). Остается записать обновленный MBR на место и закрыть дескриптор устройства. Все! После перезагрузки все изменения вступят в силу, а может быть и не вступят... Загрузчик жестоко мстит за малейшие ошибки проектирования и чтобы не потерять содержимое своих разделов, для начала лучше попрактиковаться на VM Ware или любом другом эмуляторе PC. Под Windows 9x, кстати говоря, трюк с CreateFile не работает. Но там можно воспользоваться симуляцией прерываний из DMPI или обратится к ASPI-драйверу. Оба способа подробно описаны в моей книге "Техника защиты компакт-дисков от копирования". И хотя в ней речь идет о CD, а не о HDD, жесткие диски программируются аналогичным способом. Отладка загрузчика Отлаживать код загрузчиков невероятно трудно. Загрузчик получает управление задолго до запуска операционной системы, когда никакие отладчики еще не работают. Несколько лет назад это представляло огромную проблему и при разработке навороченных загрузчиков приходилось либо встраивать в них интегрированный мини-отладчик, либо выискивать ошибки руками, головой и карандашом. С появлением эмуляторов все изменилось. Достаточно запустить BOCHS и отлаживать загрузчик, как и любую другую программу!Рисунок 5. Внешний вид эмулятора BOCHS, отлаживающего загрузочный сектор. Заключение Программирование загрузчиков - одна из тех немногих областей, в которых применение ассемблера действительно оправдано. Языки высокого уровня для этого слишком абстрагированы от оборудования и недостаточно гибки. Вот почему хакеры так любят возиться с загрузчиками, добавляя сюда множество новых фич - таких, например, как автоматическая загрузка с CD-ROM или SCSI-винтов, противодействие вирусам, парольная защита с шифрованием данных и т.д. Здесь действительно есть, где развернуться и показать себя. Но читать о новых идеях скучно и неинтересно. Намного приятнее генерировать их самостоятельно. Так чего же мы сидим?!Интересные ссылки
3
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
217 / 53 / 4
Регистрация: 03.08.2013
Сообщений: 278
|
|
| 12.10.2013, 16:53 | |
|
Интересно было бы знать,как подобное реализовать на CD-R или CD-RW диске? на дискетах мозгодолбательства с файловой системой обычно не возникает.вот не удается мне записать на сидюк бинарник в сыром виде без всяких файловых систем. хотя образ диска вполне спокойно запускается в Virtualbox.монтирую в ultraISO.
1
|
|
|
217 / 53 / 4
Регистрация: 03.08.2013
Сообщений: 278
|
|
| 12.10.2013, 23:32 | |
|
Хм,вышло в общем одно интересное явление.Мой загрузчик все же загрузился с CD-R диска.С CD-RW этот фокус почему-то не удался.Не смотря на это, диск стал читабельным,что безусловно радует.Выходит,с CD-дисками работать даже легче,чем с дискетами.
0
|
|
|
780 / 412 / 75
Регистрация: 29.03.2013
Сообщений: 853
|
||
| 14.10.2013, 17:46 | ||
1
|
||
|
Просто Лис
|
|||||||||||
| 16.11.2013, 11:54 | |||||||||||
|
Немного нубских вопросов про загрузочный сектор:
И дальше программа обращается к этой переменной? Например, здесь:
Программа будет нормально работать используя новое значение переменной или не будет работать?
0
|
|||||||||||
|
85 / 61 / 29
Регистрация: 15.05.2013
Сообщений: 189
|
|
| 05.12.2013, 10:57 | |
|
Линуксовый fdisk записывает идентификатор по смещению 1B8h. Или это я что-то путаю?
Добавлено через 7 минут ps -- Disk identifier: 0x3e15e148 0001b0 00 00 00 00 00 00 00 00 48 e1 15 3e 00 00 00 00 >>fdisk.c<< static void dos_write_mbr_id(unsigned char *b, unsigned int id) { store4_little_endian(&b[440], id); }
0
|
|
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 06.12.2013, 08:41 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Чтобы не было обвинений в плагиате предупреждаю сразу, всё нижеследующее взято на сайте asmdev.narod.ru, автор Андрей Валяев <dron@infosec.ru>, материалы были в форме рассылки, поэтому подвергнуты минимальной литобработке.
Создание операционной системы на ассемблере
Глава #1 В этой главе вы не увидите исходных текстов готовых программ, это все еще только предстоит написать при вашем активном участии. Начнем с написания ядра. Ядро будет ориентированно на UNIX-подобные операционные системы. Для простоты с самого начала будем стремиться к совместимости с существующими системами. Задача состоит в следующем: Сделать, по возможности, компактное, надежное и быстрое ядро, с максимальным эффектом используя возможности процессора. Писать будем в основном на Ассемблере. Для начала разберемся, как устроены системы .Ядро состоит из следующих компонентов:
Системы с "микроядром" строятся по модульному принципу, имеют обособленное ядро, и механизм взаимодействия между драйверами устройств и процессами. По такому принципу строятся системы реального времени. Примерно так сделан QNX или HURD. Монолитное ядро имеет более жесткую внутреннюю структуру. Все установленные драйвера жестко связываются между собой, обычно прямыми вызовами. По таким принципам строятся обыкновенные операционные системы типа Linux, FreeBSD. Естественно, не все так четко, идеального монолитного или "микроядра" нет, наверное, ни в одной системе, просто системы приближаются к тому или иному типу ядра. Очень хотелось бы, чтобы то, что делаем, больше походило на первый тип ядер. Немного углубляемся в аппаратные возможности компьютеров .Один, отдельно взятый, процессор, в один момент времени, может исполнять только одну программу. Но к компьютерам предъявляются более широкие требования. Мало кто, в настоящее время, удовлетворился однозадачной операционной системой (к каким относился DOS, например). В связи с этим разработчики процессоров предусмотрели мультизадачные возможности. Возможность эта заключается в том, что процессор выполняет какую-то одну программу (их еще называют процессами или задачами). Затем, по истечении некоторого времени (обычно это время меряется микросекундами), операционная система переключает процессор на другую программу. При этом все регистры текущей программы сохраняются. Это необходимо для того, чтобы через некоторое время вновь передать управление этой программе. Программа при этом не замечает каких либо изменений, для нее процесс переключения остается незаметен. Для того чтобы программа не могла, каким либо образом, нарушить работоспособность системы или других программ, разработчики процессоров предусмотрели механизмы защиты. Процессор предоставляет 4 "кольца защиты" (уровня привилегий), можно было бы использовать все, но это связано со сложностями взаимодействия программ разного уровня защиты. Поэтому в большинстве существующих систем используют два уровня. 0 - привилегированный уровень (ядро) и 3 - непривилегированный (пользовательские программы). Всем этим обеспечивается надежное функционирование системы и независимость программ друг от друга. Теперь немного поподробнее про устройство ядра. На "Собственно ядро" возлагаются функции менеджера памяти и процессов. Переключение процессов - это основной момент нормального функционирования системы. Драйвера не должны "тормозить", а тем более блокировать работу ядра. Windows - наглядный пример того, что этого нельзя допустить! Теперь о драйверах. Драйвера - это специальные программы, обеспечивающие работу устройств компьютера. В существующих системах (во FreeBSD это точно есть, про Linux не уверен) предусматриваются механизмы прерывания работы драйверов по истечении какого-то времени. Правда, все зависит от того, как написан драйвер. Можно написать драйвер под FreeBSD или Linux, который полностью блокирует работу системы. Избежать этого при двухуровневой защите не представляется возможным, поэтому драйвера надо будет тщательно программировать. В нашей работе драйверам уделим очень много внимания, поскольку от этого в основном зависит общая производительность системы. Системные вызовы - это интерфейс между процессами и ядром (читайте-железом). Никаких других методов взаимодействия процессов с устройствами компьютера быть не должно. Системных вызовов достаточно много, на Linux их 190, на FreeBSD их порядка 350, причем большей частью они совпадают, соответствуя стандарту POSIX (стандарт, описывающий системные вызовы в UNIX). Разница заключается в передаче параметров, что легко будет предусмотреть. Естественно, нельзя сделать ядро, работающее одновременно на Linux и на FreeBSD, но по отдельности совместимость вполне реализуема. Прикладным программам абсолютно безразлично, как системные вызовы реализуются в ядре. Это облегчает для нас обеспечение совместимости с существующими системами. В следующей главе поговорим о защищенном режиме процессора, распределении памяти, менеджере задач и рассмотрим, как это сделано в существующих системах. Вопросы
Глава #2 В этой главе поговорим об архитектуре современных процессоров и о предоставляемых средствах защиты. Понимание этого будет необходимо нам, когда перейдем непосредственно к программированию операционной системы. Как процессор работает с памятью? Для начала небольшое предисловие. В процессорах имеются базовые регистры, которые могут задавать смещение. На 16-битной архитектуре максимальное смещение могло быть до 64 килобайт, что, в общем-то, не много и вызывало определенные трудности (разные модели памяти, разные форматы файлов). Так же, в 16-битной архитектуре присутствовали сегментные регистры, которые указывали адрес сегмента в памяти. В процессорах, начиная с i386, базовые регистры стали 32-х битными, что позволяет адресовать до 4 гигабайт. Сегментные регистры остались 16-битными, и в защищенном режиме они не содержат адреса! они содержат индекс дескриптора. В реальном режиме сегментные регистры работают так же, как и на 16-битных процессорах. В реальном режиме сегментные регистры непосредственно указывают на адрес начала сегмента в памяти. Это позволяет нам, без каких либо преград, адресовать 1 мегабайт памяти. Но создает определенные трудности для защиты. А защищать нужно многое. Например, не можем пользовательским программам дать возможность непосредственно обращаться к коду или данным ядра. Так же нельзя давать возможность пользовательским программам обращаться к коду или данным других пользовательских программ, поскольку это может нарушить их работоспособность. Для этого был изобретен защищенный режим работы процессора, который появился в процессорах i286. Защищенность этого режима заключается в следующем: Сегментный регистр больше не указывает на адрес в памяти. В этом регистре теперь задается индекс в таблице дескрипторов. Таблица дескрипторов может быть глобальная или локальная (применяется в многозадачных системах для изоляции адресного пространства задач) и представляет собой массив записей, по 8 байт в каждой, где описываются адреса, пределы и права доступа к сегментам. Про адрес ничего не буду говорить, и так все ясно. Что такое предел? В этом Поле описывается размер сегмента. При обращении за пределы сегмента процессор генерирует исключение (специальное прерывание защищенного режима). Так же исключение генерируется в случае нарушения прав доступа к сегменту. Поле прав доступа описывает возможность чтения/записи сегмента, возможность выполнения кода сегмента, уровень привилегий для доступа к сегменту. При обращении к сегменту из дескриптора берется базовый адрес сегмента и складывается со смещением сегмента. Так получается линейный 32-х разрядный (в i286 - 24-х разрядный) адрес. Для i286 на этом процесс получения адреса завершается, линейный адрес там равен физическому. Для i386 или выше это справедливо не всегда. Страничная организация памяти. В процессорах, начиная с i386, появилась, так называемая, страничная организация памяти. Страница имеет размер 4 килобайта или 4 мегабайта. Большие страницы могут быть только в pentium или выше. Не знаю только, какой толк от таких страниц. Если возможность страничной адресации не используется, то линейный адрес, как и на i286, равен физическому. Если используется - то линейный адрес разбивается на три части. Первая, 10-битная, часть адреса является индексом в каталоге страниц, который адресуется системным регистром CR3. Запись в каталоге страниц указывает адрес таблицы страниц. Вторая, 10-битная, часть адреса является индексом в таблице страниц. Запись в таблице страниц указывает физический адрес нахождения страницы в памяти. последние 12 бит адреса указывают смещение в этой странице. В страничных записях, как и в дескрипторных записях, есть служебные биты, описывающие права доступа, и некоторые другие тонкости страниц. Одной из важных тонкостей является бит присутствия страницы в памяти. В случае не присутствия страницы, процессор генерирует исключение, в котором можно считать данную страницу из файла или из swap раздела. Это сильно облегчает реализацию виртуальной памяти. Более подробно про все это можно прочитать в книгах по архитектуре процессоров. Вернемся к операционным системам. Многозадачность. Многозадачные возможности в процессорах так же появились в процессорах, начиная с i286. Для реализации этого, процессор для каждой задачи использует, так называемый, "сегмент состояния задачи" ("Task State Segment", сокращенно TSS). В этом сегменте, при переключении задач, сохраняются все базовые регистры процессора, сегменты и указатели стека для трех уровней защиты (для каждого уровня используется свой стек), сегментный адрес локальной таблицы дескрипторов ("Local descriptor table", сокращенно LDT). В процессорах, начиная с i386, там еще хранится адрес каталога страниц (регистр CR3). Так же этот сегмент обеспечивает некоторые другие механизмы защиты, но о них пока не будем говорить. Операционная система может расширить TSS, и использовать его для хранения регистров и состояния сопроцессора. Процессор при переключении задач не сохраняет этого. Так же возможны другие применения. Что из всего этого следует? Не будем ориентироваться на процессор i286, поскольку 16-битная архитектура и отсутствие механизма страничного преобразования сильно усложняет программирование операционной системы. К тому же, таких процессоров давно уже никто не использует. ![]() Ориентируемся на i386 или более старшие модели процессоров, вплоть до последних. Ядро системы при распределении памяти оперирует 4-х килобайтными страницами. Страницы могут использоваться самим ядром, для нужд драйверов (кэширование, например), или для процессов. Программа или процесс состоит из следующих частей:
Все сегменты разбиваются на страницы. Сегмент кода имеет постоянный размер. Сегмент данных может увеличиваться в сторону больших адресов. Сегмент стека, поскольку растет вниз, увеличивается в сторону уменьшения адресов. Страницы памяти для дополнительных данных или стека выделяются системой по мере необходимости. Очень интересный момент При выполнении программы операционная система делает следующие действия:
Еще один интересный момент Когда в системе загружается две или более одинаковых программы - нет необходимости для каждой из них выделять место для кодового сегмента, они спокойно могут использовать один код на всех.Глава #3 В этой главе поговорим, о порядке загрузки операционных систем. Процесс загрузки, естественно, начинается с BIOS. При старте процессор находится в реальном режиме, следовательно больше одного мегабайта памяти адресовать не может. Но это и не обязательно. BIOS проверяет устройства, с которых может производиться загрузка. Порядок проверки в современных BIOS устанавливается. В список устройств могут входить Floppy disk, IDE disk, CDROM, SCSI disk... Вне зависимости от типа устройства суть загрузки одна... На устройстве обнаруживается boot sector. Для CDROM это не совсем справедливо, но про них пока не будем говорить. BootSector загружается в память по адресу 0:7с00. Дальнейшее поведение BootSector'а зависит от системы. Загрузка Linux. Для Linux свойственно два способа загрузки:
Загрузка FreeBSD. Принципиальных отличий для FreeBSD, конечно, нет. основное отличие состоит в том, что ядро, как и модули ядра являются перемещаемыми и могут быть загружены или выгружены в процессе загрузки системы. Порядок загрузки примерно следующий:
Давайте по порядку рассмотрим, как грузятся системы от Microsoft. Загрузка DOS. boot sector DOS загружает в память два файла: io.sys и msdos.sys. Названия этих файлов в разных версиях DOS различались, не важно. Файл io.sys содержит в себе функции прерывания int 21h, файл msdos.sys обрабатывает config.sys, и запускает командный интерпретатор command.com, который в свою очередь обрабатывает командный файл autoexec.bat. Загрузка Windows 9x. Отличие от DOS заключается в том, что функции msdos.sys взял на себя io.sys. msdos.sys остался ради совместимости как конфигурационный файл. После того как командный интерпретатор command.com обрабатывает autoexec.bat вызывается программа win.com, которая осуществляет перевод системы в защищенный режим, и запускает различные другие программы, обеспечивающие работу системы. Загрузка Windows NT. boot sector NT - зависти от формата FS, для FAT устанавливается один, для NTFS - другой, в нем содержиться код чтения FS, без обработки подкаталогов.
Узнали как загружаются системы? В своей системе не будем слепо следовать какому либо из представленных здесь путей. Ради совместимости обеспечим формат ядра, аналогичный Linux. В этой системе все сделано достаточно понятно и просто. Ориентируемся на Linux. А в следующей главе поговорим о распределении памяти в системе и начнем писать свой boot sector. Глава #4 Начнаем писать свой загрузочный сектор (boot sector). Сразу скажу, что в этом исходнике опытные люди не увидят ничего особенного, может быть даже наоборот, кому-то покажется что все можно было сделать гораздо лучше, не спорю. Я не очень старался. Про законченность говорить пока рано, это все еще неоднократно будет меняться. boot sector загружается в память по адресу 0:7c00h и имеет длину 512 байт. Это не слишком много, поэтому возможности boot sector'a ограничиваются загрузкой какого либо вторичного загрузчика. Наш boot sector, по образу и подобию linux, будет загружать в память два блока. Первым является тот самый вторичный загрузчик, у нас он, как и в linux, называется setup. Вторым является собственно ядро. Этот boot sector служит для загрузки ядра с дискет, поэтому, на первых порах, он жестко привязан к диску "a:". BIOS предоставляет возможность читать по нескольку секторов сразу, но не более чем до границы дорожки. Такая возможность, конечно, ускоряет чтение с диска, но представляет собой большие сложности в программировании, так как надо учитывать границы сегментов (в реальном режиме сегмент может быть не больше, чем 64к) и границы дорожек, получается достаточно хитрый алгоритм. Пойдем немного другим путем. Читаем с диска по секторам. Это, конечно, медленнее, но здесь скорость не очень критична. За то это гораздо проще и компактнее реализуется. А теперь давайте разбираться, как это все работает.
Размеры пока произвольные, поскольку все остальное еще предстоит написать.
Так же, нулевым значением, инициализируем сегментный регистр ds.
Далее располагаются функции.
А вот следующая функция загружает с диска отдельный сектор, при этом оперируя его линейным адресом. Есть так называемое int13 extension, разработанное совместно фирмами MicroSoft и Intel. Это расширение BIOS работает почти аналогичным образом, Считывая сектора по их линейным адресам, но оно поддерживается не всеми BIOS, имеет несколько разновидностей и работает в основном для жестких дисков. Поэтому нам не подходит. В своей работе ориентируемся пока только на чтение с floppy диска, размером 1,4 мегабайта. Поэтому будем использовать функцию, которой в качестве параметров задается номер дорожки, головки и сектора.
AbsSectNo = (CylNo * SectPerTrack * Heads) + (HeadNo * SectPerTrack) + (SectNo - 1) Значит обpатное спpаведливо: CylNo = AbsSectNo / (SectPerTrack * Heads) HeadNo = остаток / SectorPerTrack SectNo = остаток + 1
восемь младших бит номера хранятся в регистре ch, два старших бита номера хранятся в двух старших битах регистра cl.
Этот boot sector, помимо того, что читает по секторам, отличается от линуксового еще и размещением в памяти. После загрузки он не перемещает себя в памяти, и работает по тому же адресу, по которому его загрузил BIOS. Так же setup загружается непосредственно следом за boot sector'ом, с адреса 7e00h, что в принципе не помешает ему работать в других адресах, если будем загружать наше ядро через LILO, например. Скомпилированную версию boot sector'а вы можете найти в файловом архиве (секция "наработки"). В следующей главе переходим к программе setup и рассматриваем порядок перехода в защищенный режим. Глава #5 Рассмотрим немного подробнее организацию памяти в защищенном режиме и поговорим о концепциях защиты. История организации памяти. Ранние модели процессоров от Intel имели 16 бит шины данных и 20 бит шины адреса. Это налагало определенные ограничения на адресацию памяти, ибо 16-бинтный регистр невозможно было использовать для адресации более чем 64 килобайт памяти. Чтобы обойти это препятствие разработчики предусмотрели сегментные регистры. Сегментный регистр хранит в себе старшие 16 бит адреса и для получения полного адреса к сегментному адресу прибавляется смещение в сегменте.
Введение защищенного режима решило эти проблемы, но ради совместимости любой из современных процессоров может работать в реальном или виртуальном режиме процессора i8086. Защита. Для обеспечения надежной работы операционных систем и прикладных программ разработчики процессоров предусмотрели в них механизмы защиты. В процессорах фирмы Intel предусмотрено четыре уровня привилегий для программ и данных. Нулевой уровень считается наиболее привилегированным, третий уровень - наименее. Так же в защищенном режиме совсем иначе работает механизм преобразования адресов. в сегментном регистре теперь хранится не старшие биты адреса, а селектор. селектор представляет из себя индекс в таблице дескрипторов. И кроме этого содержит в себе несколько служебных бит. Формат селектора такой:
В процессорах Intel одновременно в системе может существовать две дескрипторных таблицы: Глобальная (Global descriptor table или GDT) и Локальная (Local descriptor table или LDT). GDT существует в единственном экземпляре. Адрес и предел GDT хранятся в специальном системном регистре (GDTR) в 48 бит длиной (6 байт). LDT может быть индивидуальная для каждой задачи, или общая для системы, или же ее вообще может не быть. Адрес и размер LDT определяется в GDT, для обращения к LDT в процессоре существует специальный регистр (LDTR), но в отличии от GDTR он имеет размер 16 бит и содержит в себе селектор из GDT. Поле TI (Table indicator) селектора определяет принадлежность селектора GDT (0) или LDT (1). Поле RPL (Requested privilege level) определяет запрашиваемые привилегии. Дескрипторы сегментов Дескрипторные таблицы состоят из записей по 64 бита (8 байт) в каждой. Формат дескриптора таков:
Базовый адрес - 32 бита (24 бита для i286). Определяет линейный адрес памяти, с которого начинается сегмент. В отличие от реального режима этот адрес может быть указан с точностью до байта. Предел - 20 бит (16 бит для i286). Определяет размер сегмента (максимальный адрес, по которому может быть произведено обращение, это справедливо не всегда но об этом чуть позже). 20-битное поле может показаться не очень то большим для 32-х битного процессора, но это не так. Оно не всегда показывает размер в байтах. Но и об этом чуть позже. Байт прав доступа:
TSS - это сегмент состояния задачи (Task state segment) о них поговорим в следующей главе. Шестой байт дескриптора, помимо старших бит предела, содержит в себе несколько битовых полей.
И снова защита. Немного терминологии: Уровень привилегий может быть от 0(высший) до 3(низший). Следовательно повышение уровня привилегий соответствует его уменьшению в численном эквиваленте, понижение - наоборот. В дескрипторе содержатся биты DPL, которые определяют максимальный уровень привелегий для доступа к сегменту. В селекторе содержится RPL - то есть запрашиваемый уровень привилегий. RPL секущего кодового сегмента (хранится в регистре cs) является уровнем привилегий данного процесса и называется текущим уровнем привилегий (CPL) Прямые обращения к сегментам возможны при соблюдении следующих условий:
Эпилог. Тема конечно очень сложна для понимания. В следующих главах концентрируем внимание на таких моментах. Интересующиеся люди могут почитать дополнительную, более подробную информацию по защите в литературе по микропроцессорам фирмы Intel.Глава #6 В этой главе продолжим разговор о защищенном режиме процессора, узнаете, что такое шлюзы. А так же вкратце поговорим о виртуальном режиме процессора 8086. В 4-ой главе, когда я расписывал вам, как писать boot sector, я допустил одну достаточно серьезную ошибку, которую признаю и благодарю Bug Maker'а, за то, что обратил на это мое внимание. В процедуре load_sector я, первым делом, делю номер сектора на количество секторов на дорожке. Для деления используя беззнаковую команду div, предварительно расширяя ax в dx:ax знаковой командой cwd. Правда если учесть что максимальное количество секторов на гибком диске не превышает 2880, то старший, знаковый, бит ax всегда нулевой. Но, тем не менее, ошибка потенциальная. Этот фрагмент кода стоит писать так:
![]() Но это еще не все.. при написании boot sector'а я говорил, что это совсем не окончательная версия. Так оно и получается. Из бутсектора мы уберем код загрузки kernel. Этим будет заниматься программа setup. Следовательно, boot sector'у осанется только считать setup и запусить его... Даже если сделать более корректную обработку ошибок чтения, у нас остается около 250 байт на всякие развлечения... ![]() А setup должен будет уметь достаточно многое. В него будет встроена поддержка файловой системы, поддержка выполняемых форматов файлов. Мы собираемся делать микроядро, и setup'у придется загружать помимо ядра еще несколько дополнительных программ, которые понадобятся нам для нормального старта системы. Но об этом позже. А теперь продолжаем разбираться с защищенным режимом. Шлюзы В предыдущей главе, когда говорили о дескрипторах и дескрипторных таблицах ни словом не упомянули о дескрипторной таблице прерываний (Interrupt description table или IDT). Эта таблица так же состоит из дескрипторов, но в отличии от LDT и GDT в этой таблице могут размечаться только шлюзы. В защищенном режиме все прерывания происходят через IDT. Традиционная таблица векторов прерываний здесь не используется. Формат дескрипторов шлюзов отличается от дескриптора сегмента. Для начала рассмотрим шлюз вызова.
Селектор и смещение задают адрес вызываемой функции, при этом селектор должен присутствовать либо в GDT либо в активной LDT. Параметр "Количество слов стека" служит для передачи аргументов в вызываемую функцию, при этом соответствующее количество слов копируется из стека текущего уровня привилегий в стек уровня привилегий вызываемой функции. Это поле использует только младшие 5 бит четвертого байта. Остальные биты должны быть нулевыми. Обращаться к такому шлюзу, если дескриптор не расположен в IDT, можно только командой call far, при этом указываемое в команде смещение игнорируется. А селектор должен указывать на дескриптор шлюза вызова. Шлюз прерывания и шлюз ловушки имеют одинаковый формат, отличаются между собой типами в байте прав доступа. В отличии от шлюза вызова эти шлюзы не содержат в себе Количества слов стека, поскольку прерывания бывают аппаратными и передача в них параметров через стек - бессмысленна. Эти шлюзы используются обычно только в IDT. Шлюз задачи содержит в себе значительно меньше информации. Во втором и третьем байте дескриптора записывается селектор TSS (Сегмента состояния задачи). Поле прав доступа заполняется аналогично другим шлюзам, но с соответствующим типом. Остальные поля дескриптора не используются. При вызове такого шлюза происходит переключение контекста задачи. При этом вызывающая задача блокируется и не может быть вызвана до тех пор, пока вызванная задача не вернет ей управление командой iret. Про правила доступа к шлюзам я говорил в прошлой главе, и в этот раз я закончу на этом. в следующей главе расскажу про прерывания более подробно. Виртуальный режим процессора 8086. Для возможности запуска из защищенного режима программ, предназначенных для реального, существует так называемый "Виртуальный режим процессора 8086". При этом полноценно работают механизмы преобразования адресов защищенного режима. А так же многозадачные системы, которые могут одновременно выполнять как защищенные задачи, так и виртуальные. При этом адресация в виртуальной задаче осуществляется традиционным для 8086 методом - сегмент/смещение. Обращение к прерываниям осуществляется через IDT, но таблица прерываний реального режима может быть обработана из функций, шлюзы которых размещаются в IDT. Обращение виртуальной задачи к портам так же может быть отслежено через прерывания защищенного режима. При обращении к запрещенным портам происходит исключение. При желании может быть обеспечена абсолютно прозрачная работа нескольких виртуальных задач в одной мультизадачной среде. Но мы этой возможностью не будем пользоваться, и в своей работе будем рассчитывать на программы исключительно защищенного режима. Глава #7 Исключения защищенного режима Исключения или системные прерывания существовали еще в самых первых моделях процессоров от Intel. Вот их список:
Введение защищенного режима потребовало введения дополнительных исключений. В защищенном режиме первые 32 вектора прерываний зарезервированы для исключений. Не все они используются в существующих процессорах, в будующем возможно их будет больше. Системные прерывания в защищенном режиме делятся на три типа: нарушения (fault), ловушки (trap) и аварии (abort). Итак в защищенном режиме у нас существуют следующие исключения:
Нарушения возникают вследствии несанкционированных или неправильных действий программы, предполагается, что ошибки можно исправить и продолжить выполнение программы с инструкции, которая вызвала ошибку. Ловушки возникают после выполнения инструкции, но тоже подразумевают исправление ошибочной ситуации и дальнейшую работу программы. Аварии возникают в случае критических нарушений, после этого программа уже не может быть перезапущена и должна быть закрыта. Но иногда в случае ошибки или ловушки программа тем не менее не может продолжить свое выполнение. Это зависит от тяжести нарушения и от организации операционной системы, которая обрабатывает исключения. И если ошибка или ловушка не может быть исправлена, программу так же следует закрыть. При возникновении исключения процессор иногда помещает в стек код ошибки, по которому обработчик исключения может проанализировать и, возможно, исправить возникшую ошибку. Все исключения обрабатываются операционной системой. В случае микроядерных систем этим занимается микроядро. Микроядерные системы В первых главах уже касались этой темы, но тогда ограничились буквально несколькими словами. Теперь двигаемся именно в сторону микроядерности, значит стоит поподробнее рассказать, что это такое. Принцип микроядерности заключается в том, что ядро практически не выполняет операций, связанных с обслуживанием внешних устройств. Эту функцию выполняют специальные программы-сервера. Ядро лишь предоставляет им возможность обращаться к устройствам. Помимо этого ядро обеспечивает многозадачность (параллельное выполнение программных потоков), межпроцессное взаимодействие и менеджмент памяти. Приложения (как и сервера) у нас работают на третьем, непривилегированном кольце и не могут свободно обращаться к портам ввода/вывода или dma памяти. Тем более не могут сами устанавливать свои обработчики прерываний. Для использования ресурсов процессы обращаются к ядру с просьбой выделить необходимые ресурсы в их распоряжение. Осуществляется это следующим образом: Для обеспечения доступа к портам ввода/вывода используются возможности процессоров, впервые появившиеся intel 80386. У каждой задачи (в сегменте состояния задачи (TSS)) существует карта доступности портов ввода/вывода. Приложение обращается к ядру с "просьбой" зарегистрировать для нее диапазон портов. Если эти порты до тех пор никем не были заняты, то ядро предоставляет их в распоряжение процесса, помечая их как доступные в карте доступности ввода/вывода этого процесса. DMA память, опять таки после запроса у ядра, с помощью страничного преобразования подключается к адресному пространству процесса. Настройка каналов осуществляется ядром по "просьбе" процесса. Доступ к аппаратным прерываниям (IRQ) осуществляется сложнее. Для этого процесс порождает в себе поток (thread), и сообщает ядру, что этот поток будет обрабатывать какое-то IRQ. При возникновении аппаратного прерывания, которое обрабатывает всетаки ядро, данный процесс выходит из состояния спячки, в котором он находился в ожидании прерывания, и ставится в очередь к менеджеру процессов. Такие потоки должны иметь более высокий приоритет, чем все остальные, дабы вызываться как можно скорее. Но, как я говорил, ядро выполняет еще некоторые функции, немаловажная из которых - это межпроцессное взаимодействие. Оно представляет из себя возможность процессов обмениваться сообщениями между собой. В отличии от монолитных систем в микроядерных системах межпроцессное взаимодействие (Inter Process Communication или IPC) это едва ли не основное средство общения между процессами, и поскольку все драйвера у нас такие же процессы, микроядерное IPC должно быть очень быстрым. Быстродействие IPC достигается за счет передачи сообщений без промежуточного буферизирования в ядре. Либо непосредственным переписыванием процессу-получателю, либо с помощью маппинга страниц (если сообщения большого размера). Менеджер памяти имеет как бы две стороны. Первая сторона - внутренняя, распределение памяти между приложениями, организация свопинга (который тоже осуществляется не ядром непосредственно, а специальной программой-сервером) никаким образом не интересует остальные программы. Но другая сторона - внешняя служит именно для них. Программы могут запросить у ядра во временное пользование некоторое количество памяти, которое ядро им обязательно предоставит (в разумных пределах... гигабайта два... не больше... . Или же программы могут запросить у ядра какой-то определенный участок памяти. Это бывает необходимо программам-серверам. И это требование ядром также вполне может быть удовлетворено при условии, что никакая другая программа до того не забронировала этот участок памяти для себя.Глава #8 В этой главе поговорим о файловых системах. Файловая система - это немаловажный момент в операционной системе, они бывают разные, различаются по производительности, надежности, по-разному экономно используют пространство. Есть много файловых систем, которые нам, в принципе, подойдут (EXT2FS, FFS, NTFS, RaiserFS и много других), есть так же файловые системы, которые нам вообще не подойдут (FAT). В процессе развития нашей операционной системы мы создадим поддержку и для них, но для начала надо остановиться на чем-то одном. Этой одной файловой системой будет EXT2FS. В этой главе подробно рассмотрим файловые системы FAT, и более подробно файловую систему Linux (ext2). Поскольку наша операционная система будет юниксоподобная, то файловые системы FAT нам никак не подходят, поскольку они не обеспечивают мер ограничения доступа, и по сути своей не являются многопользовательскими. Про остальные файловые системы я ограничусь лишь основными моментами. Так же я не стану затрагивать тему разделов диска. Обсудим это в другой раз. Основные принципы файловых систем Все устройства блочного доступа (к которым относятся жесткие или гибкие диски, компакт диски) при чтении/записи информации оперируют секторами. Для жестких или гибких дисков размер сектора равен 512 байт, в компакт-дисках размер сектора равен 2048 байт. Сектора являются физической единицей информации для носителя. Для файловых систем такое распределение часто бывает не очень удобно, и в них вводится понятие кластера. Кластеры часто бывают больше по размеру, чем сектора носителя. Кластеры являются логической единицей файловых систем. Правда, не всегда они называются кластерами. В ext2 кластеры называются просто блоками, но это не столь важно. Для организации кластеров файловые системы хранят таблицы кластеров. Таблицы кластеров, естественно, расходуют дисковое пространство. Помимо этого, дополнительное дисковое пространство расходуется под каталоги файлов. Эти неизбежные расходы в разных файловых системах имеют разную величину. Но об этом мы поговорим ниже. Файловые системы на базе FAT (File Allocation Table) Этот тип файловых систем разработала фирма Microsoft достаточно давно. Вместе с первыми DOS... С тех пор неоднократно натыкались на различные препятствия и дорабатывались в соответствии с требованиями времени. Теперь пойдет небольшой экскурс в историю. ![]()
Общий формат файловой системы на базе FAT таков:
Общий размер диска определяется следующим образом: Если значение Total_Sectors равно 0, то раздел более 32 мегабайт и его длина в секторах храниться в Big_Total_Sectors. Иначе размер раздела показан в Total_Sectors. Таблица FAT начинается с сектора, номер которого храниться в Reserved_Sectors и имеет длину Sectors_Per_FAT; при 16-битном FAT размер таблицы может составлять до 132 килобайт (или 256 секторов) (в FAT12 до 12 килобайт). Вторая копия FAT служит для надежности системы... но может отсутствовать. После таблицы FAT следует корневая директория диска. Размер этой директории ограничен Root_Entries записями. Формат записи в директории таков:
Далее на диске следуют кластеры файловой системы. Из записи в директории берется первый номер кластера, с него начинается файл. В FAT под этим номером может содержаться либо код последнего кластера (0xffff или 0xfff для FAT12) либо номер кластера, следующего за этим. При записи файла из FAT выбираются свободные кластеры по порядку от начала. В результате возникает фрагментация файловой системы, и существенно замедляется ее работа. Но это уже выходит за тему рассылки. Все выше сказанное про FAT справедливо для FAT12 и FAT16. FAT32 более существенно отличается, но общие принципы организации для нее примерно такие же. VFAT ничем не отличается от FAT16, для хранения длинных имен там используется однеа запись в директории для хранения короткого имени файла и несколько записей для хранения длинного. Длинное имя храниться в unicode, и на запись в директории приходится 13 символов длинного имени, причем они разбросаны по некоторым полям записи, остальные поля заполняются с таким расчетом, чтобы старые программы не реагировали на такую запись. С первого взгляда видна не высокая производительность таких файловых систем. Не буду поливать грязью Microsoft, у них и без меня достаточно проблем... К тому же и у них есть другие разработки, которые не столь плохи. Но о них мы поговорим ниже... А сейчас давайте посмотрим на ext2fs. Правда, эта файловая система несколько другого уровня, и сравнивать ее с FAT - нельзя. Но обо всем по порядку.Ext2fs (Расширенная файловая система версия 2) Linux разрабатывался на операционной системе Minix. В ней была (да и есть) файловая система minixfs. Система не очень гибкая и достаточно ограниченная. После появления Linux была разработана (на базе minixfs) файловая система extfs, которую в скором времени заменила ext2fs, которая и используется в большинстве Linux, по сей день. Для начала давайте рассмотрим основное устройство этой файловой системы:
Super block содержит в себе информацию о файловой системе и имеет следующий формат:
Об остальных полях чуть попозже. А теперь рассмотрим группы дескрипторов файловой системы. Формат дескриптора группы таков:
В суперблоке храниться количество блоков в группе (s_blocks_per_group). Битовая карта имеет соответствующий размер в битах (занимает она не более блока). и в зависимости от размера блока может содержать информацию об использовании 8, 32 или 132 мегабайт максимум. Дисковое пространство раздела разбивается на группы в соответствии с этими значениями. А групп, как я уже упоминал, может быть до 32... что позволяет создавать разделы, в зависимости от размера блока, 256, 1024 или 4096 мегабайт соответственно. В битовую карту блоков группы входят так же те блоки, которые используются под саму карту, под карту inode и под таблицу inode. Они сразу помечаются как занятые. Теперь давайте разберемся, что такое inode. В отличии от FAT информация о файле здесь храниться не в директории, а в специальной структуре, которая носит название inode (информационный узел). В записи директории содержится только адрес inode и имя файла. При этом на один inode могут ссылаться несколько записей директории. Это называется hard link. Формат inode таков:
Первые 10 inode зарезервированы для специфического использования. Для корневой директории в этой файловой системе не отводится заранее отведенного места. Любая, в том числе и корневая директория в этой файловой системе является по сути своей обыкновенным файлом. Но для облегчения поиска корневой директории для нее зарезервирован inode номер 2. В этой файловой системе в отличие от FAT существуют методы защиты файлов, которые обеспечиваются указанием идентификаторов пользователя и группы, а так же правами доступа, которые указываются в inode в поле i_mode. За счет нескольких групп блоков уменьшается перемещение головки носителя при обращении к файлам, что увеличивает скорость обращения и уменьшает износ носителя. Да и сама файловая система организована так, что для чтения файлов не требуется загрузка больших объемов служебной информации, Что тоже не может не сказаться на производительности. Примерно так же устроены файловые системы FFS, HPFS, NTFS. Но в их устройство я не буду вдаваться. И так уже глава очень большой получается. ![]() Но в недавнее время появился еще один тип файловых систем. Эти системы унаследовали некоторые черты от баз данных и получили общее название "Журналируемые файловые системы". Особенность их заключается в том что все действия, производимые в файловой системе фиксируются в журнале, который правда съедает некоторый объем диска, но это позволяет значительно повысит надежность систем. В случае сбоя проверяется состояние файловой системы и сверяется с записями в журнале. В случае обнаружения несоответствий довести операцию до конца не составляет проблем, и отпадает необходимость в ремонте файловой системы. К таким файловым системам относятся ext3fs, RaiserFS и еще некоторые. Глава #9 Эта глава посвящена чтению файлов с файловой системы ext2fs. Эту систему мы, скорее всего, возьмем за базовую для начала. FAT для наших целей мало подходит. Тот boot sector, который публиковался до этого - можно забыть, от него уже почти ничего не осталось. Связано это с тем, что мы отошли от linux, наша система будет совсем другой. Я, конечно, предвижу трудности связанные с переносом программного обеспечения. Возможно продумаем возможность эмуляции существующих операционных систем. Время покажет. Так же прошу меня простить, что мы занимаемся тут всякой ерундой с бутсекторами и файловыми системами, но до сих пор так и не начали писать собственно ядро. Задача эта не столь, тривиальна и нужно многое продумать, чтобы не было потом горько и обидно за бесцельно написанный код. Чтение ext2fs В предыдущей главе описывалась структура этой файловой системы. В файловой системе присутствует Super Block и дескрипторы групп. Эта информация хранится в начале раздела. Super Block во 2-м килобайте, дескрипторы групп - в третьем. Первый килобайт для нужд файловой системы не используется и может быть целиком использован для boot sector'а (правда он уже будет не сектор, а килобайт . Но для этого следует подгрузить второй сектор boot'а.А для инициализации файловой системы нам нужно загрузить super block и дескрипторы групп, они же понадобятся нам для работы с файловой системой. Это все можно загрузить одновременно, как мы и сделаем.
В es засылается адрес, следующий за загруженным загрузочным сектором (Загружается он, как мы помним, по адресу 7c00h, и имеет длину 200h байт, следовательно свободная память начинается с адреса 7e00h, а сегмент для этого адреса равен 7e0h). В ax засылается номер сектора с которого начинается блок (в нашем случае это первый сектор, загрузочный сектор является нулевым). в cx засылается длина загружаемых данных в секторах (1 - дополнительная часть boot sector'а, 2 - Super Block ext2, 2 - дескрипторы групп. Всего 5 секторов). Теперь вызовем процедуру инициализации файловой системы. Эта процедура достаточно проста, и проверяет только соответствие magic номера файловой системы и вычисляет размеры блока для работы.
Номер блока нам надо преобразовать в номер сектора, для этого мы умножаем его на длину блока в секторах. А в cx у нас уже записана длина блока в секторах, то есть все готово для вызова процедуры load_block. После считывания блока мы модифицируем регистр es, чтобы последующие блоки грузить следом за этим... в принципе модифицирование указателя можно перенести в другое место, в процедуру загрузки файла, это будет наверное даже проще и компактнее, но сразу я об этом не подумал. ![]() Но пошли дальше... основной структурой описывающей файл в ext2fs является inode. Inode хранятся в таблицах, по одной таблице на каждую группу. Количество inode в группе зафиксировано в супер блоке. Итак, процедура загрузки inode:
Кратко рассмотрю вспомогательные функции:
В этой функции стоит проверка количества загруженных блоков, для того чтобы вовремя выйти из процедуры считывания.
Функция ddir_blocks в точности аналогична этой, только для считывания вызывает не dir_blocks, а idir_blocks, поскольку адреса блоков в ней дважды косвенны. Но мы еще не рассмотрели самого главного. Процедуры, которая по пути файла может загрузить его с диска. Начнем.
Если файл не регулярный, то это может быть директорией. Это проконтролируем ниже.
Вот и весь алгоритм. Не смотря на большой размер этого повествования, код занимает всего около 450 байт. А если убрать параноидальные функции, то и того меньше. Не стоит пытаться откомпилировать этот код, все эти модули вы сможете найти на нашем сайте, ссылка на который приведена ниже. Здесь я все это привел для того чтобы объяснить как и что. Надеюсь у меня это получается хоть как-то. Если кто-то что-то не понимает - пишите мне, мой адрес вы всегда можете найти чуть ниже. В следующей главе рассмотрим форматы выполняемых файлов, используемые в unix. Это нам тоже потребуется на этапе загрузки. В этой главе речь пойдет о форматах выполняемых файлов. Будут рассмотрены два формата: ELF и PE, и немного коснемся распределения памяти. Формат ELF В данном обзоре мы будем говорить только о 32-х битной версии этого формата, ибо 64-х битная нам пока ни к чему. Любой файл формата ELF (в том числе и объектные модули этого формата) состоит из следующих частей:
Теперь рассмотрим типы, используемые в заголовках ELF файлов:
![]() Теперь про программные секции. Формат записи таблицы программных секций таков:
Загрузка формата ELF С заголовком мы немного разобрались. Теперь я приведу алгоритм загрузки бинарного файла формата ELF. Алгоритм схематический, не стоит рассматривать его как работающую программу. int LoadELF (unsigned char *bin)
Формат PE Во многом он аналогичен формату ELF, ну и не удивительно, там так же должны быть секции, доступные для загрузки. Как и все в Microsoft формат PE базируется на формате EXE. Структура файла такова:
Нас интересует немного другое, заголовок PE. Структура его такая:
И главное что большинство из этих полей не используется. (Кто так строит?) Нет, они, конечно, имеют назначение, вполне известное, но моя тестовая программа, например, в полях pe_code_base, pe_code_size и тд содержит нули но при этом прекрасно работает. Напрашивается вывод, что загрузка файла осуществляется на основе таблицы объектов. Вот о ней то мы и поговорим. Таблица объектов следует непосредственно после PE заголовка. Записи в этой таблице имеют следующий формат:
В общем, этой информации уже достаточно для загрузки бинарного файла. Загрузка формата PE
И опять таки многие моменты не освещаются, так как выходят за пределы темы. Но теперь стоит немного поговорить про существующие системные особенности. Системные особенности Не смотря на гибкость средств защиты, имеющихся в процессорах (защита на уровне таблиц дескрипторов, защита на уровне сегментов, защита на уровне страниц) в существующих системах (как в Windows, так и в Unix) полноценено используется только страничная защита, которая хотя и может уберечь код от записи, но не может уберечь данные от выполнения. (Может быть, с этим и связано изобилие уязвимостей систем?) Все сегменты адресуются с нулевого линейного адреса и простираются до конца линейной памяти. Разграничение процессов производится только на уровне страничных таблиц. В связи с этим все модули линкуются не с начальных адресов, а с достаточно большим смещением в сегменте. В Windows используется базовый адрес в сегменте - 0x400000, в юникс (Linux или FreeBSD) - 0x8048000. Некоторые особенности так же связаны со страничной организацией памяти. ELF файлы линкуются таким образом, что границы и размеры секций приходятся на 4-х килобайтные блоки файла. А в PE формате, не смотря на то, что сам формат позволяет выравнивать секции на 512 байт, используется выравнивание секций на 4к, меньшее выравнивание в Windows не считается корректным. продолжение
4
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 06.12.2013, 12:15 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Глава #11 Процесс загрузки. То, что я до сих пор сделал пока рассчитано только на работы с дисками 1,4Мб, то есть с флопами. Это конечно ограничение в некоторой степени, но пока система еще далеко не готова, этого достаточно. Естественно это еще не окончательный вариант. Да и можно ли говорить об окончательности программных продуктов? Нет предела совершенству. ![]() В обязанности бутсектора входит следующее:
В файловой системе EXT2 с этим не возникает никаких проблем, поскольку первый килобайт файловой системы не используется. В FAT это немного сложнее. Служебная структура, именуемая Boot Sector Record (BSR), содержит в себе все необходимые поля для выделения для загрузочного сектора места более чем 512 байт. Но как это сделать при форматировании, стандартными средствами, я не нашел. И если формат диска не соответствует каким-то внутренним представлениям Windows, то содержимое такого нестандартного диска может быть испорчено. Выход был найден случайно. Как оказалось утилита format хоть и не имеет таких параметров командной строки, но перед форматированием берет информацию из BSR. И если предварительно заполнить эту структуру (с нужными нам параметрами), а потом уже форматировать, то все получается так, как хочется нам. Таким образом, у меня получилось сделать диск, у которого два сектора зарезервированы (там будет размещаться boot), и одна копия FAT. Ну теперь давайте по порядку рассмотрим все этапы работы бутсектора. Загрузка с диска дополнительной части кода и служебной информации файловой системы Бутсектор загружается БИОСом по адресу 0:7c00h занимает он 512 байт. Память начиная с адреса 0:7e00h свободна. но в эту память мы загрузим второй сектор бута. Одновременно загружается информация необходимая для обслуживания файловой системы. Для EXT2 дополнительно необходимо загрузить два килобайта (суперблок и дескрипторы групп), для FAT немного больше - 4,5 килобайта (первая копия FAT).
. И далее все зависит от файловой системы.
Функции обслуживания файловых систем имеют одинаковый интерфейс. Cобственно их всего две fs_init и fs_load_file. Естественно у них различаются реализации, но в процессе компиляции выбирается используемая файловая система. Для совместного использования нам никак не хватит одного килобайта, да и не за чем это. Загрузка с диска файла сценария (конфигурации) загрузки Из-за сложности VFAT (FAT с длинными именами) он не реализован. Все имена на диске FAT должна иметь формат 8.3 В файловой системе FAT я не оперирую принятыми в MS системах именами дисков и при указании пути использую путь относительно корневой директории диска (как это делается в юникс системах). Файл конфигурации у нас пока называется boot.rc и находится в каталоге /etc. Формат у этого файла достаточно нестрогий. Из-за нехватки места в boot секторе там сделана реакция только на ключевые слова, которыми являются:
Предварительно проинициализировав файловую систему
Загрузка с диска ядра и модулей Про этот момент я не буду особо расписывать, желающие могут посмотреть в исходниках, которые в скором времени появятся на сайте. Скажу только, что программа анализирует файл конфигурации, в соответствии с ключевыми словами загружает ядро (которое может быть в единственном экземпляре) и любое количество модулей. Общий объем ядра и модулей ограничен свободным размером базовой памяти (около 600к). Перейдем к предпоследнему пункту. Переход в защищенный режим Бутсектор не особо беспокоится об организации памяти в системе - это забота ядра. Для перехода в защищенный режим он описывает всего два сегмента: сегмент кода и сегмент данных. оба сегмента имеют базовый адрес - 0 и предел в 4 гигабайта (это нам пригодиться для проверки наличия памяти). Перед переходом в защищенный режим нам необходимо включить адресную линию A20. По моим сведениям этот механизм ввели в пору 286 для предотвращения несанкционированных обращений к памяти свыше одного мегабайта (непонятно зачем?). Но поскольку это имеет место быть - нам это нужно обрабатывать, иначе каждый второй мегабайт будет недоступен. Делается это почему-то через контроллер клавиатуры (еще одна загадка).
Теперь процессор находится в защищенном режиме и уже не оперирует сегментами, а оперирует селекторами. Селекторов у нас всего три. Нулевой - недопустим. восьмой является селектором данных и шестнадцатый - селектором кода. После этого управление можно передать ядру. дальше со всем этим будет разбираться оно. Передача управления ядру Здесь вообще все просто. Когда мы загрузили ядро, в файле ядра мы определили адреса сегмента кода и сегмента данных. Не смотря на то, что ядро имеет вполне конкретные смещения в сегменте (которые задаются при компиляции), код инициализации ядра рассчитан на работу без привязки к адресам. Это нужно для определения количества памяти, после перевода ядра на свои адреса доступ ко всей памяти будет для ядра затруднен в связи с включением механизма страничного преобразования. Итак, переходим к выполнению кода ядра.
Так как сегмент кода у нас занимает всю виртуальную память, нам не важно где находится ядро (хотя мы знаем, что оно было загружено в базовую память). Мы просто передаем ему управление. О ядре мы начнем говорить в следующем выпуске. С загрузчиком мы практически закончили. Он уже обладает достаточной для нас функциональностью. В этой главе Определение количества памяти. Динамическое распределение памяти в процессах. Определение количества памяти через BIOS .Ну, начнем с исторических функций. Давным-давно, когда даже Билл Гейтс говорил что 640 килобайт хватит всем, но не у всех были эти 640 килобайт. в биосах существовала функция определения количества базовой памяти.int 12h Выходные параметры:
Сейчас уже вряд ли кому придет в голову, что базовой памяти может быть меньше 640 килобайт. но мало ли... ![]() Появлялись новые процессоры, и размеры памяти стали расти. в связи с чем появилась функция определения количества расширенной памяти. int 15h fn 88h Входные параметры:
Но, опять таки, появились новые процессоры. 16 мегабайт стало мало. Вследствие этого появилась еще одна функция BIOS: int 15h fn 0E801h Входные параметры:
Здесь производители BIOS видимо оказались неединодушны. Некоторые версии в ax и bx возвращают 0, это значит что размер памяти следует определять из cx, dx. Но видимо и 4 гигабайт оказалось мало. В новых BIOS появилась еще одна функция. int 15h fn 0E820h Входные параметры:
Формат структуры таков:
![]() Но в заключение скажу следующее. Все функции в случае ошибки (если функция не поддерживается) возвращают установленный флаг cf. В случае отсутствия новых функций необходимо обращаться к более старым. Функции BIOS не работают в защищенном режиме, поэтому все эти операции необходимо производить еще до перехода в защищенный режим. Определение размера памяти другими способами Помимо функций BIOS есть еще много других способов. Самый простой - помсмотреть память самому. Делается это из защищенного режима, страничное преобразование должно быть выключено, адресная линия A20 должна быть включена.Можно замерить объем памяти от нуля, но поскольку в первом мегабайте есть дыры (видеопамять, биосы, просто дыры), удобнее делать это начиная с первого мегабайта. Вовсе не обязательно проверять каждый байт, достаточно проверять один байт на какое-то определенное количество памяти. Определенным количеством памяти можно посчитать мегабайт, но лучше (хотя и медленнее) за единицу памяти принять одну страницу памяти (4к). Во избежание неприятностей память лучше не разрушать, а восстанавливать в первоначальном виде. делается это примерно так:
Из защищенного режима можно воспользоваться содержимым CMOS, некоторые ячейки в нем BIOS заполняет определенными при начальном тесте системы значениями. Но здесь все не так однозначно как хотелось бы. Разные версии BIOS могут хранить значения в разных местах.
Динамическое распределение памяти Почти любое приложение пользуется динамически выделяемыми блоками памяти (известная, наверное, всем функция malloc в c). Сейчас мы поговорим о том, как это все работает. Подходить к этому можно по разному, но принцип везде прослеживается один. На каждый блок памяти необходимо иметь структуру, описывающую занятось блока, его размер. В примитивной реализации это может выглядеть так, как это сделано в DOS. В ДОСе вся память на равных правах принадлежит всем запущенным программам. Но чтобы операционная система могла как-то контролировать использование памяти, в ДОСе применяются MCB (Memory Control Block). Формат этого блока таков:
Размер блока указывается в параграфах в поле SizeParas. Такая структура вполне подходит для ограниченной по размерам памяти DOS, но для приложений она не очень то применима. Разница состоит в том, что в случае ДОС, чтобы найти блок свободной памяти (Такие блоки помечаются нулевым OwnerId), необходимо пройти по всем блокам от начала цепочки, до тех пор, пока не встретится свободный блок соответствующего размера. В ДОСе имеется функция, с помощью которой можно получить адрес первого блока (Base MCB) (int 21h, fn 52h). Столь медленный поиск не страшен для DOS, у которого количество блоков редко превышает несколько десятков, но в приложениях поиск по цепочке блоков может быть достаточно долгой процедурой. Поэтому в приложениях обычно применяется другой алгоритм, который заключается в следующем. (Я рассмотрю наиболее быстрый алгоритм, вариантов, конечно, может быть множество): У каждого блока, как я уже говорил, есть два основных параметра: размер и флаг занятости. Оба эти параметра размещаются в одном двойном слове памяти. Поскольку как начало блока, так и его размер обычно выравниваются на четное число байт, младшие биты размера остаются неиспользуемыми (всегда равны нулю) и флаг занятости размещается в одном из них. Этот параметр блока размещается перед началом и по окончанию блока. Начальный параметр следующего блока соответственно будет размещен непосредственно после конечного параметра предыдущего, что позволит анализировать цепочку блоков с одинаковым успехом в обоих направлениях. Свободные блоки памяти размещаются в списках в соответствии со своим размером. Размер блоков в списках увеличивается в геометрической прогрессии. К примеру, в первом списке хранятся блоки до 16 байт длиной, во втором до 32-х байт длиной и так далее. Такая система позволяет, зная размер необходимого блока, сразу же выбирать из соответствующего списка подходящий блок и не требует поиска по всем блокам. Для организации списков к блоку добавляются несколько параметров (поскольку блок свободен, и его внутреннее пространство может быть использовано для любых целей, эти параметры размещаются в самом блоке). К этим параметрам относятся ссылка на следующий свободный блок в списке, и номер списка в котором находится блок. (Это позволяет ускорить удаление блока из списка). Для выделения блока необходимого размера сперва проверяется список соответствующего размера, в котором может потребоваться поиск блока. Если соответствующий список пуст, то проверяется следующий список, в котором уже не требуется проводить поиска, поскольку любой блок заведомо больше нужного размера. Найденный пустой блок делится на две части, вторая - не нужная часть оформляется как свободная и помещается в соответствующий список, а первая часть оформляется как занятая и возвращается программе. Из-за необходимости введения дополнительных параметров для свободных блоков памяти минимальный размер блока не может быть меньше 8 байт. Даже если пользователь захочет получить блок меньшего размера, выделится блок в 8 байт длиной. При освобождении блока, если предыдущий или последующий блоки пусты, он объединяется с ними в один блок и добавляется в список соответствующего размера. Использованные окружающие блоки удаляются из тех списков, в которых они были записаны ранее. Для того, чтобы предотвратить попытку объединения первого блока памяти (при его освобождении) с предшествующим ему, перед первым блоком ставится параметр с флагом занятости. То же самое делается и для последнего блока памяти, но только после него.
4
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 11.02.2014, 06:28 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Нестандартный загрузчик Статья Рустэма Галеева aka Roustem от 21.07.2003 с сайта WASM.RUДанная статья предназначена для тех, кто хочет подробнее узнать о процессе начальной загрузки компьютера и поэкспериментировать с ним. Никакого специального программного обеспечения не потребуется: все описываемые действия проделываются с использованием отладчика debug, входящего в состав Windows 95/98/ME/NT/XP. Проделав описанные в статье действия на своем компьютере, вы сможете создать вспомогательную программу wb.com и установить в реестре ее ассоциацию с расширением файлов .bot, что позволит одним щелчком мыши переносить созданные с помощью debug файлы на дискету, сделав ее загружаемой. Начальная загрузка После проверки программой BIOS подключенного оборудования управление передается процедуре начальной загрузки с дисков, доступ к которой можно получить через прерывание INT 19h. Данная процедура загружает всего один сектор (первый) с нулевой дорожки нулевой головки, размещая его в памяти по адресу 7С00h, и передавая управление после загрузки сектора по этому же адресу. Ответственность за дальнейшую загрузку компьютера ложится на код, содержащийся в этом секторе.Совершенно очевидно, что из-за ограниченного объема сектора (512 байт) загрузочный код разнообразием не блещет и в основном сводится к операции загрузки с диска в оперативную память дополнительных секторов, содержащих ядро операционной системы, и передаче управления по соответствующему адресу памяти. Кроме кода загрузки, в стандартном загрузочном секторе содержится также приведенный ниже в таблице блок параметров BIOS с данными о форматировании диска.
Загрузочный код Приступим к созданию нашего загрузчика. Первым делом надо загрузить весь код с дискеты в оперативную память, затем передать ему управление. При этом необходимо учесть, что мы не можем воспользоваться услугами операционной системы - можно использовать лишь низкоуровневые функции BIOS. Для работы с дисками существуют функции прерывания INT 13h, при вызове которых используются следующие регистры:
Работа с дисководом для гибких дисков имеет свои особенности; это довольно медленное устройство, дискеты можно вынимать, поэтому ошибки случаются сравнительно часто (например, при обращении к дисководу мотор не успевает "разогнаться"), поэтому операции чтения или записи при ошибках обычно повторяют по 3 раза, и лишь после трех последовательных неудач выдают сообщение об ошибке конечному пользователю. Для наших целей мы обойдемся без использования файловой системы. Используем простую линейную модель: весь код у нас будет записан последовательно за загрузочным сектором - сектора 2-18 нулевой дорожки со стороны нулевой головки (в предположении, что используется стандартная дискета на 1,44 Мб), затем сектора 1-18 нулевой дорожки со стороны первой головки; далее переходим на первую дорожку со стороны нулевой головки и т.д. Считывание, естественно, должно производиться в том же порядке. При этом необходимо где-то записать количество секторов, которые необходимо таким образом считать; сохраним это значение в двух байтах после блока параметров BIOS (со смещением 3Eh). Не забудьте, что загрузочный сектор размещается в памяти, начиная с адреса 7C00; это значит, что в памяти число секторов, которые необходимо прочитать с дискеты, будет находиться по адресу 7C3E, а с адреса 7C40 будет код. По адресу же 7C00 должна находится команда безусловного перехода
Итак, по адресу 7C40h размещается следующий код (все числа в коде - шестнадцатеричные):
Пора приступить к вводу и ассемблированию программы; для этого, как я уже говорил, используем отладчик debug. Однако сначала нужно вместо текстовых меток расставить действительные значения адресов памяти, а сделать это можно только с помощью "двух проходов". При первом проходе вместо реальных значений адресов подставляются произвольные числа; необходимо только следить, чтобы они отличались от настоящих адресов не слишком радикально (особенно в случаях команд ближних условных переходов: их можно использовать лишь при переходах в пределах 128 байт). Составляем таблицу, в которую вписываем все метки, встречающиеся в нашей программе; по мере набора программы и "прохождения" соответствующих меток проставляем в таблице рядом с каждой меткой ее действительный адрес. Затем повторно вводим все те команды, которые содержали метки, уже с реальными значениями адресов. В случае с "реальным" ассемблером всей этой канителью занимается компилятор. В нашем случае, поскольку вся эта работа была уже проделана автором, вы можете просто воспользоваться уже готовыми адресами, поверив мне на слово, что это действительно те самые адреса, которые нужны. Итак, начинаем работать. Щелкните на кнопке "Start" ("Старт") и выберите пункт "Run" ("Выполнить"). Наберите в командной строке debug. Откроется окно сеанса DOS с черточкой - приглашением отладчика debug. Программа должна начинаться у нас с адреса 7C00, поэтому набираем:
Сначала надо дать нашему шаблону имя, скажем, "template.bot". О расширении .bot немного позже, сейчас же присвоим это имя:
Программа готова, но запустить ее в таком виде нам не удастся. Начало нашей программы должно быть записано в загрузочном секторе, причем так, чтобы сохранить блок параметров BIOS. Дело не только в том, что штатными средствами операционной системы этого сделать нельзя; дело еще и в том, что с помощью отладчика debug можно ассемблировать и сохранять небольшие исполняемые файлы, но они будут в формате COM. Формат COM предполагает, что начало файла соответствует смещению 100h, и debug записывает программу на диск соответствующим образом. Поскольку наш загрузчик (как и вообще любой загрузчик) размещается в памяти, начиная с адреса 7С00, debug сохранит в нашем bot-файле перед началом собственно программы 7B00h байт "мусора". Поэтому придется создать вспомогательную программу wb.com (от "Write Boot"), чтобы сохраненный нами файл в "формате" .bot адекватным образом переписать на дискету. Вспомогательная программа Алгоритм действий следующий. При запуске программы wb.com ей в командной строке в качестве параметра передается название bot-файла, который необходимо скопировать на дискету. Далее открываем этот файл с использованием функции 3Dh прерывания DOS 21h, и сохраняем в памяти дескриптор открытого файла. Файловый указатель перемещаем в позицию 7B00h (пропуская "мусор" в начале файла). Считываем первые 512 байт (будущий загрузочный сектор), и сохраняем его в отдельном буфере, поскольку, во-первых, нам надо будет добавить туда реальный блок параметров BIOS, считанный из загрузочного сектора дискеты (иначе для повторного использования в DOS или Windows дискету придется форматировать заново), а во-вторых, по смещению 3E (непосредственно после блока параметров) нам необходимо поместить число записанных на дискету секторов (после их успешной записи). Для этой цели загрузочный сектор дискеты также считываем и сохраняем в отдельном буфере; данные блока параметров BIOS (смещения с 3h по 3Eh) копируем из второго буфера в первый. Далее организуем цикл:
Приступим к написанию кода. Область данных расположим в начале файла, поэтому первой командой будет безусловный переход для обхода этих данных:
Непосредственно после данных расположим универсальную процедуру вывода сообщений на экран. Для этой цели используем функцию 40h прерывания DOS 21h.
ASCIIZ-формат представляет собой строку в кодировке ASCII, завершающуюся двоичным нулем. Имя bot-файла будет передаваться в командной строке; как получить к нему доступ? Здесь нам придется использовать так называемый префикс программного сегмента, который операционная система размещает в памяти перед каждой COM- или EXE- программой при ее запуске. Префикс программного сегмента имеет начальное смещение 0 и размер 256 (100h) байт (именно поэтому COM-файлы начинаются со смещения 100h). Начиная со смещения 80h в префиксе программного сегмента располагается область, называемая буфером передачи данных (DTA). В первом байте этого буфера размещается длина строки параметров программы. Начиная со второго байта размещаются введенные символы (если таковые имеются), а затем следует всевозможный "мусор". Таким образом, в нашем случае после имени программы (wb.com) будет следовать пробел, затем имя bot-файла - по смещению 80h будет число, на 1 превышающее число букв в имени файла. Само имя начинается со смещения 82h. Этот адрес можно записать в регистр DX для функции открытия файла; однако сначала надо в конце имени файла (по смещению 81h + число символов в имени, т.е. число, хранящееся по адресу [80h]) поместить 0. Такую несколько громоздкую конструкцию закодируем следующим образом:
Итак, продолжаем:
В частности, подобную процедуру можно проделать, набрав данные и процедуру вывода сообщений (до адреса 7BDh), затем набрав процедуру открытия файла (до адреса 7D5h), затем после перемещения файлового указателя (до адреса 7E6h), после чтения загрузочного сектора (до адреса 812h), после цикла копирования секторов (до адреса 887h). На каждом этапе "своя" часть функциональности должна быть обеспечена. В любом случае должно выводиться начальное сообщение. Затем, если в командной строке не было указано имя существующего файла (при необходимости с полным путем к нему), должно выводиться сообщение "Ошибка открытия файла". После реализации чтения загрузочного сектора должно появиться обращение к дисководу и т.д. Для отладки используем тот же debug, для этого, собственно, он и предназначен. Чтобы вывести ассемблированный код, необходимо набрать 'u [адрес] <Enter>' и сравнить введенный код с тем, который должен быть. Особенно тщательно следует следить за соответствием адресов ссылок и данных. При попытке дизассемблировать область данных мы получим бессмыслицу - для отображения данных служит команда 'd [адрес] <Enter>', данные отображаются в виде шестнадцатиричных чисел. Обработка ошибок в нашей программе сведена к минимуму, поэтому она требует корректного к себе обращения. При запуске вместе с названием файла wb (расширение указывать не обязательно) через один пробел должно следовать название bot-файла. Необходмо помнить, что формат загружаемого файла нашей программой не проверяется; она с одинаковым успехом сможет открыть файл любого формата - и txt, и bmp, и jpg, и exe и т.д. - и скопирует его на дискету, убрав начальные 7B00h байтов. Отладка программы wb.com - это только полдела; она может успешно записать загрузочный сектор дискеты, а вот то, что мы туда записываем, само может потребовать отладки. Для этой цели и предназначается относительно простая программа "test.bot". Сначала эту программу можно составить так, чтобы в ней был всего один дополнительный сектор. После записи "test.bot" на дискету с помощью wb.com следует перезагрузить компьютер, оставив дискету в дисководе. При этом последовательность загрузки с помощью BIOS Setup должна быть установлена в порядке "A, C". Если надпись "Sector 2" отображается, можно добавить еще несколько секторов и проверить их работу. Данный шаг позволит убедиться, что программа wb.com правильно записывает последовательность секторов на дискету, а bot-программа - правильно их считывает. Изменения в реестре Если все работает нормально, можно несколько повысить для себя уровень сервиса при работе с этими программами. Для начала разместим wb.com в каталоге Windows (например, C:\WINDOWS). Теперь wb можно набирать, как обычную команду операционной системы, и она будет работать независимо от каталога, в котором мы находимся. Чтобы еще больше облегчить себе работу, создадим ассоциацию bot-файлов с программой wb.com. Желающие могут воспользоваться для этой цели проводником Windows, а для любителей программирования я привожу здесь соответствующий reg-файл.Откройте "Блокнот" Windows и наберите в нем следующий текст:
Теперь, если не было сделано ошибок, при двойном щелчке на имени файла с расширением .bot откроется окно DOS и появится знакомое нам приглашение вставить чистую дискету в дисковод А:. Вставив дискету и нажав любую клавишу, мы получим загрузочную дискету. Остается только пожелать успеха в ваших экспериментах с загрузочным сектором. 2002-2013 (©) wasm.ru
2
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
|
|
| 16.06.2014, 05:34 [ТС] | |
|
JobsOS Пример ОС на ассемблере. Не совместима с 21h прерыванием и работает на прерываниях BIOSЕсть функции: shutdown,format,dir,example,cls. ОС имеет виртуальный диск, объемом 1024x9 (секторы по 1024, а их всего 9). Взято здесь
0
|
|
| 16.06.2014, 05:34 | |
|
Помогаю со студенческими работами здесь
15
Загрузочный сектор, редактирование через Debug Загрузочный сектор на DVD-RW. Не происходит загрузки. Как записать данные в загрузочный сектор без использования int 13h Не получается читать загрузочный сектор. Переписать загрузочный сектор флешки Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога
Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
|
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
|
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога
В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
|
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
|
|
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога
Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
|
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога
Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
|
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования.
Часть библиотеки BedvitCOM
Использованы. . .
|
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога
SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
|