Bollywood HungamaJanhvi Kapoor, Sreeleela and Siddharth Gupta team up for Umesh Bisht’s thriller, first schedule begins in NainitalInquirerTaal Volcano records 17 earthquakes in 24 hoursCNN TürkTaksitli alışverişlerde yeni dönem: Cep telefonlarında 12 taksit sınırı değiştiPunchPolice remove Rivers DPO after station renovation by suspected cultistsDaily MaverickKATLEHONG MASS SHOOTING: Girl, 11, who survived mass shooting still has bullet lodged near her spineRTP DesportoFrancisco Cabral na final de pares do Masters 1.000 de XangaiThe Jerusalem PostIDF blocks roads leading to Gaza border after Nahala settlers attempt to build outpost overnightEgypt IndependentTemperatures drop 3°C as rain reaches CairoMalay MailFahmi: No Malaysian palm oil companies involved in burning activities in IndonesiaColliderApple TV's New Crown Jewel Officially Continues Streaming DominationSouth China Morning PostChina’s AI boom, self-sufficiency push fuel earnings surge for local chip firmsSky TG24Sciopero scuola e blocco autotrasportatori: giornata di mobilitazione da Nord a Sud. LIVE
The Daily Newsstand · Free, Always
Friday, October 16, 2026

Режимы работы x86-процессора

Translate

Этой статьей я хочу описать часть своих знаний, приобретенных на моем пути в OSDev и системном программировании. Параллельно я буду писать также документацию по CS, которую в скором времени выложу на свой GitHub.

Важно подметить, что мой путь ещё далеко не окончен и я, можно сказать, нахожусь в самом его начале. Зачем тогда я это делаю? Чтобы закрепить уже имеющиеся знания, получить критику от более опытных специалистов, а также, возможно, помочь некоторым новичкам подробно разобраться в теме.

Принцип работы процессора.

Почти все подобные статьи начинаются с краткой, часто даже с переупрощенной схемы «Кнопка запуска ПК -> BIOS -> железо -> загрузчик -> ОС». Я же хочу начать немного с другого: Как вообще работает процессор на базовом уровне?

Конечно, абсолютно все, даже не погруженные в IT люди, знают что такое бит, байт и т.д. Но как именно процессор ими оперирует? Как биты доставляются до самого кремния? Как проходят вычисления? Вот на это мы сейчас и ответим.

Как процессор оперирует битами?

На самом деле, процессор довольно глуп. Нет одной инструкции «найти подстроку». Вместо этого он использует довольно примитивные логические операции. AND, OR, XOR и т.д. Подробно я останавливаться на этом не буду — в интернете об этом достаточно много информации. Так вот, наборы таких логических операций называются инструкциями: они могут быть как сложными и долгими в рамках работы процессора, как INVLPG, так и простыми и быстрыми, как MOV или ADD. За такт ядро процессора может выполнить только 1 инструкцию (современные уже могут, но поскольку статья вводная, думаю, подобное допущение простимо), поэтому настоящего параллелизма на одном ядре не существует, вместо этого во всех современных ОС используется псевдопараллелизм.

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

Как биты доставляются до процессора?

Своеобразной «дорожкой», по которой ток доходит до процессора, являются шины: шина данных и шина адреса. Как следует из названия, по первой процессору поступают данные, с которыми нужно работать, а по второй — адрес следующей инструкции. Шины бывают разных размерностей, и в силу того, что архитектура x86 довольно стара и сохранила совместимость с предками вплоть до 16-битных процессоров, даже современные 64-битные процессоры по умолчанию стартуют в 16-битном режиме и переключить его — задача загрузчика или ОС. Так вот, это все к тому, что битность шины адреса является одним из следствий режима работы процессора.

Режимы работы процессора.

На данный момент домашние ПК могут находиться в 3 режимах: — 16-битный режим, или же real mode. Для него характерны 16-битные регистры (Это отдельная обширная тема, которой я посвящу отдельную статью), а также 16-битные машинные слова. НО 20-битная шина адреса, об этом ниже. — 32-битный режим, или же protected mode. Для него, что, думаю, очевидно, характерны 32-битные регистры, шина адреса, 32-битные машинные слова — И наконец — 64-битный режим, он же long mode. По аналогии с вышеперечисленными: 64-битные регистры, машинные слова. Физическая шина адреса же тут 52 бита, а виртуально оперирует чаще всего 48 битами иногда — 57 бит (при пятиуровневой страничной адресации, что также — тема отдельной статьи).

Real mode.

Переходим к основной части статьи — режимы работы процессора. И начнем, конечно, с real mode.

Важной особенностью этого режима является то, что из него мы имеем косвенный доступ к BIOS, а точнее, можем обращаться к нему через специальные прерывания. Таким не может похвастаться ни protected, ни long mode в силу архитектурных ограничений.

У многих вероятно уже возник вопрос: почему 16-битный режим использует 20-битную шину адреса, а главное — как? И тут не обойтись без исторической справки. 16-битная шина адреса обеспечивает доступ процессора всего лишь к 64КБ RAM, что почти не давало прироста в сравнении с предыдущими 8-битными ПК. Перед инженерами Intel возникла задача — увеличить это число хоть как-нибудь. И они пришли к идее о сегментации, сделав шину адреса 20-битной, что сразу расширило максимальный объем адресуемой памяти до 1МБ.

Сегментация.

Сегментация — модель адресного пространства, при котором память разделяется на сегменты. Сегмент — непрерывная область памяти, начало которой хранится в сегментном регистре. Нужные данные же хранятся внутри сегмента, а их позиция в нем задается смещением — числом, хранящемся в регистре общего назначения (GPR).

В этой модели памяти адрес задается не прямым “наименованием” байта, как в protected mode, а формулой:

address = segment * 16 + offset

Почему умножаем на 16? Потому что x * 16 = x << 4. На деле получается:

Сегмент: 0bXXXX XXXX XXXX XXXX
* 16 (он же << 4): 0bXXXX XXXX XXXX XXXX 0000
Сдвиг: 0b0000 YYYY YYYY YYYY YYYY
Адрес: 0bXXXX XXXX XXXX XXXX 0000 + 0b0000 YYYY YYYY YYYY YYYY

А на конкретных цифрах:

Сегмент: 0b0010 1001 0110 1001
* 16: 0b0010 1001 0110 1001 0000
Сдвиг: 0b0000 1010 0011 1010 0001
Адрес: 0b0010 1001 0110 1001 0000 + 0b0000 1010 0011 1010 0001 = 0b0011 0011 1010 0011 0001

Т.е., как я думаю уже понятно, программе напрямую по конкретному адресу в нужное место не попасть:

bits 16
main:
    mov [0xB8000], 'A' ; На экран ничего не выведется, поскольку архитектура требует адрес вида сегмент:смещение.
    
	mov ax, 0xB800
	mov es, ax
	mov di, 0
	mov [es:di], 'A' ; На экран выведется A, поскольку 0xB800 * 16 + 0 = 0xB8000, что как раз адрес VGA text buffer.

A20.

Также одной из особенностей архитектуры x86 является наличие адресной линии А20 на шине процессора, которая по умолчанию выключена, а без ее включения любые адреса выше 1МБ будут заворачиваться (wrap-around эффект). Если конкретнее — бит 20 (сама линия А20) и выше. Дальше все просто отбрасывается, и в итоге остаются только младшие 20 бит. Например:

Адрес: 0×10FFFF
Этот же адрес с выключенной A20 процессор читает как: 0×0FFFF

Поэтому, если программе нужен будет доступ к памяти выше 1МБ, эту шину обязательно нужно включить. Самый простой способ: Fast A20 gate, проворачиваемый всего в 3 строчки на ассемблере:

in al, 0×92 ; Сохраняем значение порта 0×92 — порта, 1 бит (если считать от 0) которого как раз и отвечает за нужную нам линию, хотя и другой функционал тоже имеет.
or al, 2 ; Выставляем тот же 1 бит в 1.
out 0×92, al ; Записываем получившееся обратно в порт.

На самом деле, этот вариант хоть и прост, но достаточно ненадежен, поскольку подразумевает, что бит 1 у порта всегда 0, а также не учитывает возможные ошибки. Мы платим надежностью за простоту.

Protected mode.

Protected mode - 32-битный режим процессора. Здесь уже можно линейно обращаться к памяти, в отличие от предыдущего режима. Максимальный объем адресуемой памяти увеличился до 4ГБ, а также появляется возможность включить paging. А теперь подробнее.

Сегментация.

Здесь сегментация из «адресного» принимает защитный характер, отсюда и название режима. В чем заключается «защитная роль»: — Сегментные регистры (CS, DS, ES и т.д.) теперь хранят не адрес, а селектор — ссылку на дескриптор, где теперь записаны база сегмента, лимит, права доступа и т.д. — При каждой загрузке селектора процессор сам проверяет все это и выдает ошибки при несовпадении с ожидаемым. Все без участия ОС. — Это обеспечивает гибкость адресации, когда ОС может менять дескриптор и все селекторы будут автоматически указывать на новые. А также изоляцию, когда никто не может выйти за границы своего сегмента (лимит) или без должных прав делать что-либо.

Дескрипторы — это своего рода «описатели». «Записи», в которых описаны некоторые «правила». В GDT (Global Descriptors Table) — «правила» работы с памятью и сегментами, в IDT (Interrupt Descriptors Table) — «правила» реагирования процессора на те или иные прерывания.

Особенности режима.

Для работы protected mode требует заранее настроенной GDT. Это архитектурное ограничение. Поэтому перед переходом в 32-битный режим нужно настроить хотя бы базовую глобальную таблицу дескрипторов. Каждый дескриптор имеет формат:

  • Байты 0-1. Limit, “Где заканчивается сегмент”

  • Байты 2-4. Base, “Где начинается сегмент”

  • Байт 5. Access byte, права

  • Байт 6. Флаги (старшие 4 бита) + Limit (младшие 4 бита)

  • Байт 7. Base Такая “некрасивая” структура обусловлена историей и желанием совместимости новых процессоров со старой архитектурой и программами.

Сама GDT обязана начинаться с нулевого дескриптора. А максимальный размер - 64КБ (65535 байта из-за 16-битного поля лимита), т.е. 8191 дескриптора. И, поскольку первый дескриптор нулевой, в итоге их может быть до 8190. Хотя, на деле редко используется больше нескольких десятков.

Также в этом режиме появляется возможность включить paging — страничную модель адресации памяти. Это тема для отдельной большой статьи, но тут я кратко опишу суть.

Со включением paging (Бита PG в служебном регистре CR0) процессор уже оперирует не физическими, а виртуальными адресами. В системе еще до включения paging должны быть созданы таблицы страниц. Обычно они разделяются на 4 уровня: — PML4 (Page Map Level 4). Самая большая таблица. Её адрес помещается в регистр CR3 и далее все виртуальные адреса будут находиться внутри неё до переключения на другую таблицу того самого регистра. Её записи хранят адреса на следующий уровень таблиц. — PDPT (Page Directory Pointer Table). На неё указывают записи в PML4, а сама она указывает на следующий уровень. — PD (Page Directory). Аналогично PDPT. — PT (Page Table). Записи в ней уже указывают не на следующий уровень таблиц, а на сами фреймы (4КБ) — физические области памяти, где фрейм по размеру равен странице — основной единице разбиения адресного пространства.

Т.е. это своего рода «пакет с пакетами», только в конце тебя ждет не то, что ты ищешь, а адрес того, что ты ищешь.

В каждой таблице может храниться до 512 записей, указывающих на разные таблицы следующего уровня (на фреймы в случае PT). Таким образом каждая PML4 может указывать на 512 таблиц PDPT, каждая из которых может указывать на 512 PD, которые в свою очередь указывают на 512 PT, а каждая из них — на фрейм.

Выше описана схема именно для long mode. В protected mode без PAE адресация двухуровневая (PD -> PT) по 1024 записи, а с PAE — трехуровневая (PDPT -> PD -> PT) по 512 записей.

Это очень упрощенная схема, упускающая кучу деталей, особенностей, оставляющая кучу вопросов, которая просто в общих чертах описывает логику работы. Но в рамках конкретно этой статьи подробностей не будет.

Long mode.

И последнее — 64-битный режим. Сегментация здесь уже практически не используется, а для работы обязателен уже включенный paging. И снова к подробностям.

Сегментация.

Сегментация в Long mode уже фактически не используется. Практически все сегментные регистры, которые использовались ранее, игнорируются процессором. «Активными» остаются только 2: FS и GS. Они нужны для доступа к TLS (Thread-Local Storage) и в разных ОС могут использоваться по разному.

Адресация.

Как я упоминал выше, несмотря на то, что адресная шина тут 52-битная, зачастую для адресации используется только 48 бит. Тут следует еще немного погрузиться в страничную адресацию, поскольку в Long mode используется именно она и только она. Виртуальный адрес выглядит теперь так:

0x0000124836C9BEDF
=
0b0000 0000 0000 0000 0001 0010 0100 1000 0011 0110 1100 1001 1011 1110 1101 1111

Где старшие 16 бит должны быть копией 47 бита (canonical address). Младшие 12 - смещение внутри страницы/фрейма, а каждые 9 между ними - номер записи таблицы в вышестоящем уровне. Т.е.:

0b0000000000000000 000100100 100100000 110110110 010011011 111011011111
 |CanonicalAddress|  PML4  |   PDPT   |   PD    |   PT   |    offset   |

Где трансляция (определение нужного физического адреса из виртуального) выглядит так: PML4[36] -> PDPT; PDPT[288] -> PD; PD[438] -> PT; PT[155] -> Frame; Frame + 3807 = нужный байт.

Canonical address — разделение адресных пространств. Т.е. «нижнее» пространство, где старшие 16 бит =0, принадлежит пользователю, а «верхнее» пространство, где старшие 16 бит =1, принадлежит ядру ОС (higher half). Каноническая дыра, создаваемая таким механизмом, просто огромна и съедает больше 99.99% всех возможных адресов, но даже так каноническая адресация дает 128ТБ на пользовательское пространство и столько же на пространство ядра, итого 256ТБ на всю систему, что уже запас памяти на десятилетия вперед для домашних ПК. Но уже существует 5-уровневая адресация с виртуальным адресом 57 бит, и обсуждается 6-уровневая.

Переход между режимами.

Отдельно распишу специфические условия перехода между режимами: — Для перехода из real mode в protected mode — это валидная GDT, адрес которой помещен в GDTR, а также выставление бита PE в регистре CR0 — Для перехода из protected mode в long mode — это заранее настроенная таблица страниц, валидный адрес PML4 которой помещен в регистр CR3, фактическое «включение» paging выставлением бита PG в том же CR0, установка бита PAE в регистре CR4 и бита LME в регистре EFER. — Финальным шагом каждого перехода является far jump, обновляющий CS.

Заключение.

Опыта в написании подобных статей у меня нет, поэтому, думаю, она довольно дырявая. В будущем, по мере наработки опыта, статьи будут становиться качественнее. Что касается меня, я веду свой GitHub и иногда делаю посты в ТГК. А к “опыту”, который я имею, относятся 2 моих основных проекта:

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.