
Комментарии 18
Вроде 16битный protected mode не выпиливали.
Забавно, что 32х битный автоматически приравнивается к протектед. Ушла эпоха, когда A20 считалась недокументированным хаком, а разработка защищенного режима прорывом, когда в первую очередь писали при кольца защиты
32-битный режим, или же protected mode. Для него, что, думаю, очевидно, характерны 32-битные регистры, шина адреса, 32-битные машинные слова
Шина адреса начиная с Pentium Pro через PAE - 36бит.
Хороший подход начинать не со схемы загрузки, а с того, как процессор вообще оперирует битами, тогда переходы между реальным, защищённым и длинным режимом воспринимаются гораздо естественнее. Для новичков в OSDev я бы ещё отдельно подчеркнул, что в длинный режим нельзя попасть напрямую из реального без включения страничной адресации. Планируете ли разобрать в продолжении, как устроены GDT и переход через дальний прыжок?
«Кнопка запуска ПК -> BIOS -> железо -> загрузчик -> ОС»
Хм... BIOS -> железо -- это как?
абсолютно все, даже не погруженные в IT люди, знают что такое бит, байт и т.д.
Далеко не все, и, что странное, даже среди типа ИТшников такие попадаются.
Нет одной инструкции «найти подстроку» . Вместо этого он использует довольно примитивные логические операции. AND, OR, XOR и т.д.
Вообще-то, у 8086 и всех потомков есть строковые операции, пригодные, в т.ч., и для поиска подстрок (CMPS). Им, конечно, требуется определённое "обрамление" (загрузить правильные адреса, установить счётчик символов, интерпретировать полученный результат), но, тем не менее.
Так вот, наборы таких логических операций называются инструкциями
Не логических, а просто любых действий, которые может выполнять процессор по приказу программиста. Кстати говоря, я предпочитаю переводить instruction как "команда": "инструкция" в русском языке зачастую является аналогом "manual", т.е. неким руководством к действию, но не приказом что-то сделать прямо сейчас -- в отличие от команды, которая именно приказывает (сравните: "Инструкция по эксплуатации" и "Рота, в ружьё!").
За такт ядро процессора может выполнить только 1 инструкцию (современные уже могут, но поскольку статья вводная, думаю, подобное допущение простимо), поэтому настоящего параллелизма на одном ядре не существует, вместо этого во всех современных ОС используется псевдопараллелизм.
Про последнее не понял, честно говоря. Что же касается параллелизма на уровне выполнения команд, то, во-первых, он существует (для архитектуры IA-32 -- начиная с Pentium, но если говорить шире, то впервые появился ещё в 1960-х годах, на CDC 6600 и затем IBM 360/91), а во-вторых, лучше уж ввести концептуальный порядок выполнения команд: строго одна за другой, и выполнение новой начинается лишь после завершения старой. Пока программа является однопоточной (физически выполняется на одном логическом процессоре), соблюдение концептуального порядка гарантируется аппаратурой, даже если физически выполнение команд совмещается или они вообще выполняются в другом порядке. Однако при параллельной работе на нескольких процессорах особенности выполнения команд уже надо учитывать (на IA-32/AMD64 это несложно, поскольку за очень многим следит аппаратура, на других архитектурах у программиста головной боли больше).
И, кстати, корректней говорить не о ядрах, а о логических процессорах: одно ядро может выглядеть для программиста несколькими процессорами (из-за гипертрединга).
В разных режимах работы это число также разное, а называется оно машинным словом
Неверно. Применительно ко всем процессорам x86 (начиная с 8086 и кончая любыми современными 64-разрядными) независимо от режима работы словом называются два байта (16 бит): так сложилось исторически. На других архитектурах словом может называться иная величина.
Своеобразной «дорожкой», по которой ток доходит до процессора, являются шины: шина данных и шина адреса. Как следует из названия, по первой процессору поступают данные, с которыми нужно работать, а по второй — адрес следующей инструкции. Шины бывают разных размерностей, и в силу того, что архитектура x86 довольно стара и сохранила совместимость с предками вплоть до 16-битных процессоров, даже современные 64-битные процессоры по умолчанию стартуют в 16-битном режиме и переключить его — задача загрузчика или ОС. Так вот, это все к тому, что битность шины адреса является одним из следствий режима работы процессора.
Абсолютно неверно. Во-первых, в столь явном виде, как это было в 1980-е, шин адреса и данных сейчас не существует (они, конечно, есть, но спрятаны на кристалле процессора, причём разведены очень хитро между процессорными ядрами, кэшами, контроллером памяти, мостами с внешними шинами и т.п.). Во-вторых, разрядность их определяется только и исключительно конкретной реализацией и абсолютно не зависит от режима работы процессора. Из ядра может торчать 8-разрядная шина данных (пример -- 8088, из-за чего некоторые клоуны называли его 8-разрядным микропроцессором), а может 256-разрядная -- и для программиста это совершенно незаметно. То же самое касается шины адреса: у 8086/88 она была 20-разрядной, у 80286 и 80386SX -- 24-разрядной, у 80386DX и 80486 -- 32-разрядной, ну и т.д.
Режимы работы процессора.
Неполный список. Полный выглядит так:
16-разрядный реальный режим (единственный для 8086/88 и 80186/188);
16-разрядный защищённый режим (введён в 80286);
32-разрядный защищённы режим (введён в 80386);
режим виртуального 8086 (V86) -- по сути, подрежим 32-разрядного защищённого, предназначенный для выполнения 16-разрядного кода реального режима (чтоб программы для ДОС можно было под Виндой запускать, грубо говоря). Полностью выпилен при переходе процессора в 64-разрядный режим;
"нереальный" (unreal) режим, неофициально появился в 80386 и сохраняется до сих пор, позволяя с помощью сегментных регистров FS и GS адресовать 4 Гбайта памяти, находясь в реальном режиме (вероятно, и в 16-разрядном защищённом тоже);
режим управления системой (SMM, введён в 80386SL и 80486SL);
64-разрядный защищённый режим (введён AMD, позже скопирован Intel, когда провал IA-64 aka Itanium стал очевиден).
из него мы имеем косвенный доступ к BIOS, а точнее, можем обращаться к нему через специальные прерывания. Таким не может похвастаться ни protected, ни long mode в силу архитектурных ограничений.
Неверно. У BIOS имеется ряд функций, доступных из 16- и 32-разрядных защищённых режимов, ну а UEFI, собственно, в защищённом режиме и работает (причём в просторечии его всё равно именуют BIOS, хотя это, строго говоря, неверно).
16-битная шина адреса обеспечивает доступ процессора всего лишь к 64КБ RAM, что почти не давало прироста в сравнении с предыдущими 8-битными ПК
Не RAM, т.е. оперативной памяти, а к 64 кбайтам адресного пространства памяти, а что в нём расположено -- не дело процессора (там могут быть и ОЗУ, и ПЗУ, и регистры устройств).
Не "почти не давало", а просто "не давало": основная масса 8-разрядных процессоров имела 16-разрядную шину адреса.
В этой модели памяти адрес задается не прямым “наименованием” байта, как в protected mode, а формулой:
В 16- и 32-разрядных защищённых режимах сегментация тоже используется, и физически без неё обойтись невозможно. Т.е. "прямого наименования байта" в этих режимах тоже нет.
Также одной из особенностей архитектуры x86 является наличие адресной линии А20 на шине процессора, которая по умолчанию выключена, а без ее включения любые адреса выше 1МБ будут заворачиваться (wrap-around эффект).
Вообще, изначально её не было: у 8086/88 шина адреса 20-разрядная, а её линии нумеруются A19:A0. Сворачивание происходило "автоматически": если при сложении сегмента и смещения получалось значение, превышающее по ширине 20 разрядов, т.е. превосходящее F'FFFF, старший бит терялся, поскольку линии A20 не существовало.
А вот когда делали 80286, у которого адрес был расширен до 24 разрядов (A23:A0), про это дело забыли и допустили ошибку, и в результате при сложении сегмента FFFF и смещения FFFF в реальном режиме получался адрес 10'FFEF. Это нарушало совместимость "снизу вверх" с предыдущими процессорами, поэтому разработчики IBM PC/AT добавили внешний по отношению к микропроцессору костыль -- вентиль A20 (gate A20), который блокировал передачу единицы по линии A20.
Protected mode - 32-битный режим процессора
Защищённые режимы -- и 16-, и 32-, и 64-разрядные в зависимости от того, что и как включено (ну и от модели процессора, естественно).
когда ОС может менять дескриптор и все селекторы будут автоматически указывать на новые
Не будут они "автоматически" указывать на новые: чтобы новый описатель (дескриптор) вступил в действие, после его изменения в памяти надо обязательно выполнить загрузку соответствующего сегментного регистра. Пока сегментный регистр не перезагружен, он обеспечивает обращение к сегменту, информация из которого была получена в момент его последней загрузки (т.е. содержимое описателя в памяти игнорируется).
В GDT (Global Descriptors Table) — «правила» работы с памятью и сегментами, в IDT (Interrupt Descriptors Table) — «правила» реагирования процессора на те или иные прерывания.
Помимо GDT, есть ещё и LDT.
И последнее — 64-битный режим. Сегментация здесь уже практически не используется
Она там не "практически не используется", а полностью выпилена. При работе в 64-разрядном режиме CS, DS, SS и ES вообще никак не используются, а FS и GS работают подобно базовым регистрам, а не "нормальным" сегментным (в 32-разрядной Винде они именно сегментными были, а доступ к TLS обеспечивался за счёт загрузки в них соответствующим образом сформированных описателей).
SMM - скорее часть другого измерения по привилегиям доступа (наряду с ring 0 - ring 3 и режимом гипервизора), эта тема вообще не затронута.
Но, тем не менее, режим работы :) И да, про виртуализацию таки забыл -- но я в неё никогда и не вникал (применительно к IA-32/AMD64).
Тема не затронута, поскольку я с ней ещё не знаком. Проект у меня работает пока только в ring 0 и реализация ring 3, к сожалению, будет не скоро. Но как изучу, возможно, и про это напишу
Очень благодарен, что кто то настолько детально решился разобрать статью. Было очень информативно, учту все нюансы. Большое спасибо за критику
Отредактировал статью:
Постарался исправить все фактические ошибки и учесть поправки из комментариев
Немного поправил стилистику в некоторых местах
Подробнее описал переход между режимами и unreal mode
Всем большое спасибо, кто помог найти ошибки и улучшить статью
С этой закончил, теперь приступаю к статье про регистры
Поэтому, если размер шины больше, чем нужно, то часть шины данных сверх нужного просто не используется (как в современных 64-битных ПК, когда те находятся в real mode на старте)
Вот это вот утверждение некорректно -- по всей видимости, Вы не разбираетесь в "электронной" стороне вопроса (это, если что, не наезд -- для программиста вполне обычным является не понимать, как в реальности работает железо, ведь это не его область деятельности; ну а как работа идёт на уровне транзисторов, зачастую и разработчики железа не очень хорошо понимают -- ибо на уровне транзисторов почти никогда цифровую электронику сейчас не проектируют). В реальности современные процессоры используют свои (не видимые никому, кроме разработчиков процессора) шины максимально полным образом. Скажем, если в программе написано: MOV AL,mem, т.е. выполняется загрузка всего одного байта, то, если требуемого байта нет в кэш-памяти, процессор считает из физического ОЗУ полную строку кэша, в которой будет, в т.ч., и этот байт -- а размер строки кэша обычно составляет 64 байта. Соответственно, если процессор соединён с памтяью 16-байтовой шиной, он для считывания одного-единственного байта физически выполнит четыре пересылки по 16 байтов. Ну а если требуемый байт уже лежит в кэше, он просто считает его из кэша вообще без обращения к памяти.
16-битные real и protected mode
16-битные регистры
20-битная (для real-mode) или 24-битная (для protected mode) шина адреса
Тоже не совсем корректно, как и последующий текст.
Регистры являются 16-разрядными только на 16-разрядных процессорах (80286 и младше). При работе на 80386 или более поздних в реальном или 16-разрядном защищённом режиме они всё равно будут 32-разрядными, и можно обращаться ко всем 32 разрядам. Скажем, в реальном режиме для 80386 можно написать ADD EAX,EBX -- и будут сложены два 32-разрядных регистра.
Ну а ширина шины адреса определяется типом процессора и воощбе никакого отношения к его режиму работы не имеет. Работающий в реальном режиме 80386DX использует все 32 бита адреса, просто старшие биты обычно будут равны нулю (но в нереальном режиме возможно обращение ко всем 4 Гбайтам, хотя нереальный режим -- это обычный реальный, просто с нестандартным заполнением теневых регистров FS/GS).
Вот в 64-разр процах, работающих в 16- или 32-разрядном режиме, доступа к старшим половинам регистров, кажется, нет, и они выглядят как 32-разрядные, хотя физически остаются 64-разрядными -- но утверждать не берусь, надо смотреть документацию, а мне лениво :)
Unreal mode
4.Загрузить DS/ES селектором этого дескриптора
Этот пункт, строго говоря, неверен: для нереального режима загружают FS и/или GS. Дело в том, что DS и ES постоянно перезагружаются при работе программы, а любая его загрузка в реальном режиме сносит предел и прочую скрытую информацию, т.е. лишает возможности обращения ко всей памяти. FS/GS, с другой стороны, программами реального режима не используются вообще (у 80286 и более ранних процессоров их просто не было), а программа, специально написанная для нереального режима, загрузив их в защищённом режиме, после возврата в реальный режим не будет их перезагружать, а будет лишь использовать в тех случаях, когда надо обратиться к памяти за пределами 1 Мбайта (вроде MOV AX, FS:адрес).
Большое спасибо за уточнения! Поправил статью и постарался учесть
Кстати, насчёт старших половин 64-битных регистров вы правы. Я перепроверил:
Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1, раздел 3.4.1.1.:
the upper 32 bits of 64-bit general-purpose registers are undefined in 32-bit modes
Ещё раз спасибо за критику!
Режимы работы x86-процессора