Память компьютера

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

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

ПРОЦЕССОР. БЛОК УПРАВЛЕНИЯ ПАМЯТЬЮ

Процессоры изначально заточены под сегментную организацию памяти, иначе зачем было вводить шесть сегментных регистров CS..FS. Более того, они не имеют механизмов запрещения сегментации, тогда-как страничную трансляцию можно включать\выключать битом(31-PAGE) регистра управления процессором(CR0).

В аппаратной части подсистемы памяти фигурируют 3 типа адресов: логический, линейный и физический. Из этой троицы, ЦП оперирует только логическим адресом, который использует в своих программах программист. Для трансляции остальных адресов, процессор имеет блок управления памятью - MMU (Memory Management Unit).

Логический адрес состоит из сегмента и смещения - CS:EIP, DS:ESI, ES:EDI, etc. MMU собирает эти составляющие, преобразуя лог\адрес в линейный (в диапазоне 0..N). Если в регистре(CR0) включён страничный режим, то в дело вступает транслятор страниц MMU. Если-же страничное преобразование выключено, то линейный адрес совпадает с физическим, который и выставляется процессором на внешнюю шину-адреса. Схематически это выглядит так (в сегментных регистрах лежит 2-байтный селектор сегмента, EA - смещение, тёмным выделены блоки MMU):

На этом рисунке бит 'PAGE' в регистре(CR0) имеет значение нуль, т.е. страничная трансляция отключена и вся физическая память разбита только на сегменты. Линейный адрес совпадает с физическим. Если установить 'PAGE=1', то перемычка с транслятора страниц снимается, и на сегментную организацию накладывается страничная - блоки фиксированного размера по 4Кб, которые составляют виртуальную память. Только при использовании страничной трансляции доступны 36-битные физические адреса до 64-Гбайт (PSE, PAE).

В сегментной модели, память представляется группой независимых блоков. Для адресации байта, программа использует логический адрес состоящий из селектора сегмента, и смещения. Селектор выбирает определённый сегмент, а смещение указывает на конкретный байт в пространстве выбранного сегмента:

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

ДЕСКРИПТОР - БАЗА, ЛИМИТ, ЗАЩИТА

В защищённом режиме размер сегментов может быть произвольным: от 1-байта до 4-Гбайт. Любому из них в отдельности можно задавать свои атрибуты(Access) и ограничивать доступ двойной защитой. От сюда и название режима - защищённый - Protected! Во-первых можно указать уровень привилегий (RPL), т.е. с какого из 4-х колец защиты(0-3) возможен доступ к сегменту. Во-вторых - какие можно проводить операции с его данными: чтение, запись, исполнение.

Каждый сегмент памяти описывает его-собственный

дескриптор

. Размер дескриптора 8-байт (64-бита). В нём хранится линейный адрес начала сегмента в памяти (Base=32-бит), размер сегмента (Limit=20-бит), и атрибуты защиты (Access=12-бит). При обращении к сегменту, MMU сначала проверяет значение смещения, которое не должно превышать лимит. То есть адрес не должен выходить за пределы сегмента, в противном случае ЦП сгенерит исключение.

Если с базой и атрибутами ситуация прозрачна, то к лимиту есть вопросы..

Например, как 20-ю битами определить размер сегмента в 4-Гб? Ответ - его размер указывается в единицах измерения! Среди атрибутов, в дескрипторе имеется т.н. бит гранулярности(G). Если он сброшен, то единицей измерения считается байт, если взведён - то 4-Кбайтная страница. Отсюда следует, что при G=0 размер\лимит сегмента ограничен значением 1.048.576 байт (20-бит = 1Мб), а при G=1 включается множитель(4Кб): 1048576*4096=4 Гбайт.

ТАБЛИЦЫ ДЕСКРИПТОРОВ - GDT, LDT, IDT

Обычно программа занимает несколько сегментов памяти: кода(CS), данных(DS), стека(SS). У каждого из них свой дескриптор. Итого - три., плюс три вспомогательных сегмента, на которые указывают ES\FS\GS. Внутри одной задачи (программы), все её дескрипторы собираются в Таблицу дескрипторов. Таких таблиц тоже всего три:

-1. Глобальная таблица дескрипторов(GDT) - системная и может быть только одна. Доступна всем задачам, если не нарушаются права доступа. Обычно GDT включает дескрипторы сегментов кода и данных ОС, сегментов состояния задач(TSS). Под дескрипторную таблицу текущей задачи(LDT) выделяется отдельный сегмент. Дескриптор этого сегмента хранится в GDT.

-2. Локальная таблица(LDT) для каждой задачи своя. Их кол-во определяется кол-вом активных задач в системе: LDT-1,2,3,,N. К локальным дескрипторам может обращаться только та задача, в таблице которой эти дескрипторы прописаны. В каждый момент времени процессору доступна только одна из локальных таблиц(LDT) - таблица текущей задачи.

-3. Таблица прерываний(IDT) служит заменой таблицы векторов прерываний реального режима. Процессор обращается к ней при возникновении аппаратных исключений. Прямой доступ со стороны прикладной задачи к сегменту IDT не возможен, т.к. бит индикатора таблицы(TI) в селекторе сегмента позволяет выбирать только GDT или LDT. В этой таблице хранятся дескрипторы шлюзов-прерываний и ловушек, по аналогии с векторами реального режима.

Все эти таблицы хранятся в памяти, а их физические адреса лежат в регистрах процессора GDTR, LDTR, IDTR соответственно. Команды записи [LGDT\LLDT\LIDT] в них являются привилегированными (запись возможна только с нулевого кольца), зато чтение в PMode никак не препятствуется процессором: SGDT\SLDT\SIDT.

Кроме этих таблиц, в окружении задачи обязательно присутствует

сегмент TSS (Task State Segment)

- сегмент состояния задачи. При переключении задач, в этот сегмент сбрасывается полная инфа о текущей задаче - ccылка на предыдущую запись TSS (для восстановления приостановленной задачи), текущее состояние всех (кроме FPU) регистров ЦП, указатели на внутренний стек, битовая карта прерываний, и пр. Описание сегмента(TSS) можно найти здесь:

http://www.club155.ru/x86addr-tss

, или в манах

Intel'a Vol.3

. Селектор дескриптора(TSS) хранится в регистре(TR) процессора -

Task Register

.

Нужно отметить, что кроме дескрипторов 'своих' сегментов, в локальной таблице(LDR) присутствуют и сегменты ОС. То есть в пространстве памяти есть общие для всех сегменты. Это касается импортируемых API-функций системы. Эти функции лежат в сегментах памяти ОСи, к которым нет прямого доступа из прикладного уровня. Поэтому ОС (в зависимости от импорта) дополняет LDT текущей задачи, некоторыми дескрипторами из своей\глобальной таблицы. Такой подход исключает переключение задач при вызове API. Прикладной задаче разрешено читать только те сегменты ОСи, которые она прописала в её локальную таблицу дескрипторов(LDT).