ОСдев №10: основной загрузчик, часть 3. GDT. / программирование :: длиннопост :: разработка :: ассемблер :: Операционная система :: OSDev :: geek (Прикольные гаджеты. Научный, инженерный и айтишный юмор)

программирование geek OSDev Операционная система ассемблер разработка длиннопост 

ОСдев №10: основной загрузчик, часть 3. GDT.

Подготовительный этап закончен, можно приступать к интересному. Кроме собственно загрузки файлов наша программа должна подготовить для ОС рабочую среду. Это значит: переключить процессор в 32/64-битный режим, настроить таблицу прерываний и создать базовую GDT. Сегодня разберёмся с последним пунктом.

GDT - сокращение от Global Descriptor Table, глобальной таблицы дескрипторов. Что это такое? По сути - набор записей одинакового формата, описывающих области памяти и разрешения, которые они имеют. Упрощённо это выглядит так:

//область 0

адрес области

размер области

параметры доступа

флаги

//область 1

адрес области

размер области

параметры доступа

флаги

...

В 32/64-битном режиме дескрипторные таблицы используются вместо старой схемы адресации сегмент:смещение. Зачем? Сегмент:смещение - небезопасная технология, которая позволяет переписать любой участок памяти. Надо ли говорить, что при неосторожном обращении это легко может закончиться бедой? Дескрипторная таблица даёт возможность ограничить запись или выполнение кода в отдельных областях RAM. Дескрипторные таблицы появились как часть аппаратной защиты памяти вместе с 286 процессором.

Как это работает? После выхода из 16-битного режима процессор больше не принимает адреса в формате сегмент:смещение. Если попытаетесь так сделать - получите исключение GPT (General Protection Fault). Вместо этого в сегментном регистре процессор ожидает получить смещение дескриптора внутри ДТ. При этом для операций над этим сегментом будут действовать правила, указанные в дескрипторе. Например, попытка обратиться к памяти за пределами сегмента или запись в защищённый от записи сегмент будут вызывать исключения (кстати, про обработку исключений поговорим позже, пока давайте примем, что это фатальная ошибка, которая приведёт к остановке программы).

Кроме глобальной таблицы дескрипторов существуют ещё локальные (ЛДТ), TSS и таблицы дескрипторов прерываний (IDT). Для того, чтобы наша ОС могла начать работу, обязательно наличие только двух таблиц: GDT и IDT. Давайте теперь взглянем на GDT поподробнее. Скажу сразу, зрелище будет не очень приятное. Но начнём с лёгкого. Так как GDT - часть аппаратной схемы защиты памяти, у неё есть свой регистр: GDTR. Это 48-битный регистр, 4 байта которого предназначены для смещения GDT, а 2 - для её размера. Таким образом, GDT не может быть больше 65536 байтов в размере. Размер записи в GDT - 8 байтов, значит,< таблица может иметь максимум 8192 дескриптора. Зная всё это, хорошим тоном было бы сразу зарезервировать 64К под GDT, но в моей архитектуре ОС создаёт свои таблицы, так что сейчас я обойдусь минимумом. Минимум в данном случае - 3 дескриптора. Нулевой, сегмент кода и сегмент данных. Зачем отдельно выделять нулевой дескриптор? Дело в том, что обращение к нему в GDT приводит к, вы угадали, исключению. Это тоже своего рода мера предосторожности.

А теперь время взглянуть на структуру дескриптора. И тут, увы, наследие тяжёлого прошлого во всей красе. Ради обратной совместимости в кодом для старых процессоров дескриптор GDT превратили в кашу.

Первые два байта - это первые 16 битов границы сегмента.

Следующие три байта - первые 24 бита основания сегмента.

Следующий байт - параметры доступа. Рассмотрим ниже.

Следующий байт совмещает в себе биты 16-19 границы и флаги. Об этом тоже подробнее ниже.

Ну и последний байт - биты 24-31 основания.

Неудобно? Не то слово. Когда будем писать ядро - обязательно замутим процедуру для комфортной работы с этим месивом. К счастью, сейчас у нас статичная структура всего из трёх сегментов, так что заполнить можно и вручную. Создадим и подключим модуль GDT.inc. Как это сделать, мы рассматривали в прошлый раз. И добавим в него вот такую таблицу:

;Нулевой дескриптор, сЫ 00001л бы 00001л db 001л
с1Ь 00000000Ь с1Ь 00000000Ь с!Ь 001л
¿Дескриптор сегмента бы 0РРРР1л с!ы 00001л с!Ь 001л
дЬ 10011010Ь с!Ь 11001111Ь с!Ь 001л
¿Дескриптор сегмента бы 0РРРР1л бы 00001л с!Ь 001л
6Ь 10010010Ь 6Ь 11001111Ь с1Ь 001л
¿Биты 0-15 предела.
¿Биты 0-15


Это и есть наша GDT, ничего ужасного. Значения в нулевом дескрипторе для нас не важны, а вот остальные давайте рассмотрим подробнее. У нас есть два дескриптора: один - для кода, другой - для данных. Оба начинаются с 0 и занимают FFFFF*4Kib = 4Gib. Фактически это значит, что, начав работать, ОС сможет использовать всю память по своему усмотрению. Давайте теперь разберём параметры доступа и флаги.

Бит 1 - флаг чтения/записи. Его значение различается для сегментов кода и данных.
Для сегментов кода установленный флаг означает, что чтение разрешено.
Запись в сегменты кода запрещена всегда.
Для сегментов данных установленный флаг означает, что разрешена запись. Чтение из сегментов данных

Таким образом, значение параметров доступа 10010010b даёт нам вот что: это сегмент данных, запись в него разрешена, сегмент растёт вверх, уровень привилегий - ring0. А теперь флаги. Биты 0-3 здесь заняты границей сегмента, не обращаем на них внимания.

Бит 4 зарезервирован и должен быть равен 0.
Бит 5 указывает на 64-битный сегмент. Так как мы пока переходим в 32-битный, должен быть равен 0.
Бит 6 указывает на 32-битный сегмент. Наш выбор, устанавливаем в 1.
Бит 7 - гранулярность. Если равен 0, то значение границы сегмента используется как

Окей, теперь у нас есть GDT. Но как указать системе, что её нужно использовать? Процессор ведь не дурак, сам искать не станет. Всё просто, джентльмены из IBM в кои-то веки о нас позаботились. При помощи специальной ассемблерной команды lgdt (load GDT) мы можем передать в регистр GDTR линейный адрес таблицы и её размер. Для этого добавим перед GDT такую структуру:

60ТК_р1:г:
dы 00171п	;Размер таблицы - 1 (23 байта).
dd 00000000И	;Абсолютный адрес таблицы.,программирование,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,OSDev,Операционная система,ассемблер,разработка,длиннопост

Размер таблицы мы уже знаем, а вот адрес придётся посчитать, так что пока оставим 0 и напишем процедуру инициализации GDT:

init_GDT ргос
init_GDT endp
push eax pushfd
xor eax,eax
mov ax,offset GDT
add eax,00000500h
mov dword ptr [GDTR_ptr+2],eax
cli
lgdt pword ptr GDTR_ptr sti
popfd pop eax ret,программирование,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,OSDev,Операционная

На случай, если тут не всё очевидно, поясню. Мы помещаем в EAX смещение GDT относительно сегмента, а потом добавляем адрес сегмента*16. Это и есть линейный адрес, сохраняем его в структуре. После этого отключаем прерывания, передаём структуру процессору командой lgdt и включаем прерывания обратно. По идее прерывания можно не трогать, так как в 16-битном режиме GDT не используется, но я перестраховщик.

Собственно, на этом всё. Добавьте вызов init_GDT в конец загрузчика перед cli и дело в шляпе. Сегодня без картинки, но вот вам котик.

программирование,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,OSDev,Операционная система,ассемблер,разработка,длиннопост

Чистая дискета: https://drive.google.com/file/d/1Bold4ds8oEruHQ7fJZKHglVo7A2Vc5MR/view?
Предыдущие части:

Подробнее
;Нулевой дескриптор, сЫ 00001л бы 00001л db 001л с1Ь 00000000Ь с1Ь 00000000Ь с!Ь 001л ¿Дескриптор сегмента бы 0РРРР1л с!ы 00001л с!Ь 001л дЬ 10011010Ь с!Ь 11001111Ь с!Ь 001л ¿Дескриптор сегмента бы 0РРРР1л бы 00001л с!Ь 001л 6Ь 10010010Ь 6Ь 11001111Ь с1Ь 001л ¿Биты 0-15 предела. ¿Биты 0-15 основания. ¿Биты 16-23 основания. ¿Байт доступа. ¿Биты 16-19 предела и флаги. 32-битный сегмент, страничная гранулярность. ¿Биты 24-31 основания. кода. Основание = 000000001л, предел = 0РРРРР1л*4Кл.Ь. ¿Биты 0-15 предела. ¿Биты 0-15 основания. ¿Биты 16-23 основания. ¿Байт доступа. Чтение разрешено, исполняется с указанным уровнем привилегий, гз.п§0 ¿Биты 16-19 предела и флаги. 32-битный сегмент, страничная гранулярность. ¿Биты 24-31 основания. данных. Основание = 000000001л, предел = 0РРРРР1л*4Кз.Ь. ¿Биты 0-15 предела. ¿Биты 0-15 основания. ¿Биты 16-23 основания. ¿Байт доступа. Чтение разрешено, исполняется с указанным уровнем привилегий, гз.п§0 ¿Биты 16-19 предела и флаги. 32-битный сегмент, страничная гранулярность. ¿Биты 24-31 основания.
Бит 1 - флаг чтения/записи. Его значение различается для сегментов кода и данных. Для сегментов кода установленный флаг означает, что чтение разрешено. Запись в сегменты кода запрещена всегда. Для сегментов данных установленный флаг означает, что разрешена запись. Чтение из сегментов данных разрешено всегда. Бит 2 - флаг направления/правил доступа. Для сегментов кода 0 означает, что код может быть выполнен только с уровнем привилегий, указанным в дескрипторе. 1 - код может быть исполнен с уровнем привилегий равным или меньше указанного в дескрипторе. Не парьтесь пока, про уровни привилегий поговорим позже. Для нас это значение должно быть равно 0. Для сегментов данных установленный флаг значит, что сегмент растёт вниз (основание должно быть больше границы). Бит 3 указывает, сегмент кода или данных описывает дескриптор. 0 - сегмент данных, 1 - кода. Бит 4 должен быть установлен для сегментов кода или данных. Если он равен 0, то это системный сегмент, например, ТББ. Биты 5 и 6 вместе дают значения от 0 до 3 и указывают уровень привилегий дескриптора от гл.п§0 до гз.п§3. 0 - наивысший уровень привилегий, 3 - самый низкий. Бит 7 должен быть установлен для всех функциональных регистров. Установка его в 0 делает дескриптор нелегитимным, обращение к нему будет вызывать исключение.
Бит 4 зарезервирован и должен быть равен 0. Бит 5 указывает на 64-битный сегмент. Так как мы пока переходим в 32-битный, должен быть равен 0. Бит 6 указывает на 32-битный сегмент. Наш выбор, устанавливаем в 1. Бит 7 - гранулярность. Если равен 0, то значение границы сегмента используется как есть, но если 1, то оно умножается на 4Кл.Ь. Так как мы хотим охватить всю доступную в 32-битном режиме память, устанавливаем в 1.
60ТК_р1:г: dы 00171п ;Размер таблицы - 1 (23 байта). dd 00000000И ;Абсолютный адрес таблицы.
init_GDT ргос init_GDT endp push eax pushfd xor eax,eax mov ax,offset GDT add eax,00000500h mov dword ptr [GDTR_ptr+2],eax cli lgdt pword ptr GDTR_ptr sti popfd pop eax ret

программирование,geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор,OSDev,Операционная система,ассемблер,разработка,длиннопост
Еще на тему
Развернуть
Тоскливые звуки скрипа мозгов
koyama koyama 29.05.202117:57 ответить ссылка 0.4
Говорят, полезно для профилактики альцгеймера.
Блин, спасибо конечно за инфу, но картинки с черно белым текстом специально что бы позлить тех кто с тёмной темой или кастомными стилями?)
arkham arkham 29.05.202119:52 ответить ссылка 0.3
Сорян, чуваки, не придумал пока как лучше бороться со слетающим форматированием. Сам не в восторге.
Там где текст в несколько колонок - можно использовать таблицы как вариант. А там где нужны отступы можно невидимые символы типа пробела из трифорса, хотя запарно конечно. Ну или просто на картинке чёрный смягчить ти #202020
arkham arkham 29.05.202120:04 ответить ссылка 0.3
Думаю, что проще всего мне будет убрать контраст на картинке. Проще, чем заменять табы в исходниках на пробелы или ещё какую-нибудь невидимую херню перед вставкой сюда.
Ах ты чёрт. Накосячил. В параметрах доступа пропустил бит 0. Это бит доступа. Его значение устанавливает сам процессор когда это нужно. Можно установить в 0.
Джой значит это теперь филиал хабра? Или хабр - филиал джоя?
Scallop Scallop 29.05.202123:09 ответить ссылка 0.1
И то и другое филиал двача.
Днём пощю на Хабре, вечером на джое, ночью на дваче. Главное не перепутать.
Только зарегистрированные и активированные пользователи могут добавлять комментарии.
Похожие темы

Похожие посты
Programmers in Enterprise Company
Programmers in Startup Company
Programmers in Government 2015
but I wanna keep Windows 7
2022
please don’t leave me 
4:12 PM
start £ nfc
Admin
Internet Explorer
, _
VJ Outlook Express
U Windows Explorer Notepad ^ Paint 0 WordPad j Calculator Accessibility Wizard ^ J Tour Windows XP jg' Solitaire ,V* Windows XP Mode
Welcome to Windows XP
All Programs

Control Pane
©) Help and Support
P Search
n Run.
подробнее»

новости geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор Windows Операционная система Windows 10 Windows XP

 4:12 PM start £ nfc Admin Internet Explorer , _ VJ Outlook Express U Windows Explorer Notepad ^ Paint 0 WordPad j Calculator Accessibility Wizard ^ J Tour Windows XP jg' Solitaire ,V* Windows XP Mode Welcome to Windows XP All Programs Control Pane ©) Help and Support P Search n Run.
^ Bochs for Windows - Display
USER ,__£
m2
■+Щ
•te
ТА
Reset susPEno Rower-
Û *
ujf'tnu vvwet
ù ф
Please visit :
. http://bochs.sourceforge.net . http ://www.nongnu.org/vgab ios
Bochs UBE Display Adapter enabled
Bochs 2.6.10.sun BIOS - build: 01/05/20
^Revision: 13752 $ $Date: 2019-12-
подробнее»

программирование geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор OSDev Операционная система разработка ассемблер длиннопост

^ Bochs for Windows - Display USER ,__£ m2 ■+Щ •te ТА Reset susPEno Rower- Û * ujf'tnu vvwet ù ф Please visit : . http://bochs.sourceforge.net . http ://www.nongnu.org/vgab ios Bochs UBE Display Adapter enabled Bochs 2.6.10.sun BIOS - build: 01/05/20 ^Revision: 13752 $ $Date: 2019-12-