Virtual Memory

Oct 05, 2007 03:44

VM

Наконец-то у меня в голове появился новый материал, достаточно полный, что о нем можно сделать запись в журнале. На этот раз речь пойдет о виртуальной памяти, а точнее, о страничном преобразовании. "А что может быть необчного в страничном преобразовании?" -- спросите вы. Действительно, о правиле "10-10-12" знает любой человек, хоть раз заглядывавший в соответствующую литературу, и писать о нем совершенно не интересно. Но на этот раз речь пойдет о расширениях возможностей страничного преобразования, а именно, о возможности адресовать более четырех гигабайт физических адресов. Эту возможность предоставляют технологии PAE и PSE-36. И, чтобы не отставать от прогресса, поговорим о возможностях страничного преобразования в уже не новой технологии EM64T (т.е. о страничном преобразовании в 64битном адресном пространстве).

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

PAE
Аббревиатура PAE расшифровывается как Physical Address Extension (расширение физического адреса). Впервые технология была представлена в Pentium Pro. Наличие PAE определяется с помощью инструкции cpuid: с источником eax = 1, установленный в 1 бит 6 регистра edx говорит о поддержке PAE процессором. Включается же PAE установкой пятого бита регистра CR4 в единицу.

С помощью PAE 32битный указатель может адресовать физическую память, находящуюся выше адреса 0xFFFFFFFF (2^32 - 1, четыре гигабайта). А точнее, позволяет адресовать до шестидесяти четырех (2^36) гигабайт физической памяти. Казалось бы, как это возможно? Поговорим об этом чуть позже. Сначала посмотрим на этот процесс с т.з. аппаратной части. Когда процессор производит чтение/запись значения ячейки по какому-либо адресу, он выдает адрес ячейки на шину адреса и генерирует сигнал чтения/записи. (Все, конечно, намного сложнее, но не будем углубляться дальше.) Процессор, поддерживающий PAE имеет 4 дополнительных (к существовавшим ранее тридцати двум) контакта, на которые подается адрес. 2^32 * 2^4 = 2^36. Таким образом , процессор может обращаться к адресам, лежащим за пределами значения 2^32.

Как это происходит?
Самое главное -- понять, что любая страница может быть отображена на физический адрес, лежащий выше четырех гигабайт. Т.е., например, линейный адрес 0х0 может быть преобразован в физический адрес 0x100000000. Чтобы познакомиться с этим процессом поближе, рассмотрим структуры, которые использует процессор для трансляции линейного адреса. С одной стороны, изменения этих структур минимальны. Все так же есть каталог таблиц (далее именуемый просто "каталог") и таблицы страниц. Однако, кое-что добавлено, кое-что изменено. Теперь адрес разбивается на 4 части, и правило "10-10-12" заменено на "2-9-9-12". На индексирование элементов таблицы страниц и каталога теперь выделено 9 бит. Помимо этого, появилась новая структура -- Page Directory Pointer Table (PDPT). CR3 теперь содержит адрес таблицы каталогов, а не каталога. О ней более подробно ниже.


Рисунок 1. Интерпретация бит линейного адреса.

Для начала, разберем формат элемента таблицы страниц. Из него, как вы знаете, в конце концов берутся верхние 20 бит физического адреса страницы в обычном (10-10-12) преобразовании адреса.


Рисунок 2. Элемент таблицы страниц.

Первое, что бросается в глаза -- размер элемента страницы увеличен с тридцати двух бит до шестидесяти четырех. В принципе, это является основным моментом преобразования с использованием PAE: старшие 20 бит линейного адреса заменяются на старшие 24 бита физического. При размере страниц 4 килобайта это дает 2^24 * 2^12 = 2^36 бит физического адреса. Логично предположить, что размер таблицы страниц в таком случае должен увеличиться вдвое. Однако, это не так. Теперь таблица страниц, вместо привычных тысячи двадцати четырех элементов размером 4 байта, содержит пятьсот двенадцать, размером 8 байт. А значит, что для индексации элемента таблицы страниц теперь достаточно девяти бит линейного адреса (2^9 = 512). Таким образом, элементы таблицы страниц теперь выровнены по границе 8 байт относительно базового адреса таблицы страниц. Сама же таблица страниц осталась выровненной по границе 4 килобайта. Значения флагов, находящихся в младших двенадцати битах не изменились.

Элемент каталога претерпел аналогичные изменения. Он также расширен до восьми байт, а значит, что таблицы страниц теперь могут размещаться за пределами адреса 0xFFFFFFFF. Выбор элемента каталога осуществляется аналогично выбору элемента таблицы страниц -- 9 бит (биты с двадцать первого по двадцать девятый) умножаются на 8 и складываются с базовым адресом каталога. Каталог выровнен по границе 4 килобайта. Значения флагов, находящихся в младших двенадцати битах не изменились.


Рисунок 3. Элемент каталога таблиц.

Итак, подытожим то, что мы имеем: 12 младших бит линейного адреса -- смещение в странице, следующие за ними 9 бит -- индекс в таблице страниц, следующие 9 -- индекс в каталоге таблиц. 12 + 9 + 9 = 30. Что же происходит с оставшимися двумя битами?

Page Directory Pointer Table
Вот тут в игру вступает Page Directory Pointer Table -- таблица каталогов. Дело в том, что теперь каталогов может быть несколько, а именно -- 4. Физические адреса каталогов хранятся в таблице каталогов -- массиве из четырех 64битных элементов, каждый из которых содержит 24 старших бита физического адреса одного из каталогов таблиц. Таким образом, каждый элемент таблицы каталогов представляет собой как бы регистр CR3, но с небольшими отличиями (см. рисунок 4). Во-первых, CR3 содержал 20 старших бит физического адреса каталога таблиц, а элемент таблицы каталогов содержит 24 старших бита, что позволяет каталогам размещаться в памяти выше четырех гигабайт. Во-вторых, каждый элемент таблицы каталогов имеет бит присутствия P, позволяющий выгружать каталог таблиц из памяти. Теперь вспомним о двух, незадействованных ранее, старших битах линейного адреса. Их значение используется как индекс в таблице каталогов, что можно видеть на рисунке 1.


Рисунок 4. Элемент таблицы каталогов.

Но что же теперь содержит CR3?

CR3
Нетрудно догадаться, что CR3 (отныне именуемый PDPTR(Page Directory Pointer Table Register)) содержит физический адрес таблицы каталогов. Соответственно, изменен его формат. Старшие 27 бит CR3 теперь содержат физический адрес таблицы каталогов, два из младших пяти бит управляют кэшированием, три зарезервировано, а значит, адрес таблицы каталогов таблиц должен быть выровнен по границе 32 байта. Т.к. размер CR3 не изменился, то таблица каталогов должна находиться в пределах 32битного адресного пространства.


Рисунок 5. Регистр CR3.

Немного "математики"
При использовании PAE 32битное адресное пространство как бы разбивается на 4 части, каждую часть обслуживает свой каталог и таблица страниц. Это происходит за счет того, что количество элементов в каталоге и таблице уменьшено вдвое. И если раньше один каталог и 1024 таблицы страниц на каждый элемент каталога охватывали 32битное адресное пространство целиком, то теперь каждый каталог содержит 512 (2^9) указателей на таблицы страниц, таблица страниц, в свою очередь, содержит 512 (2^9) физических адресов. Значит, каталог и таблица страниц, теперь охватывают 2^9 * 2^9 * 2^12(размер страницы не изменился) = 2^30, т.е. 1 гигабайт. Таким образом, адреса 0 -- 3FFF FFFF обслуживает первый элемент таблицы каталогов таблиц, 4000 0000 - 7FFF FFFF -- второй, 8000 0000 - BFFF FFFF -- третий и С000 0000 - FFFF FFFF -- четвертый.

Каким путем адресовать данные выше четырех гигабайт?
Пятикнижие Интелово предлагает нам создать каталог и таблицы страниц, которые преобразуют виртуальный адрес в физический, лежащий выше четырех гигабайт, и когда нам потребуется чтение/запись этих адресов, подменять элемент таблицы каталогов, либо менять регистр CR3 целиком. Однако, аффтар думает, что никто не запрещает направить за пределы четырех гигабайт всего одну страницу, либо элемент каталога, что позволит обращаться к большим адресам "окнами" по 4 килобайта, либо 2 мегабайта соответственно.

Немного практики
К сожалению, далеко не все читатели (как, впрочем, и я) являются счастливыми обладателями планок памяти объемом более четырех гигабайт, и соответственно, не могут проверить работу режима PAE на практике. Однако, никто не запрещает нам отследить путь, который проделывает процессор, преобразовывая линейный адрес при включенном PAE. Допустим, у нас есть адрес:


Рисунок 6. Интерпретация бит линейного адреса. Пример.
Первым делом, процессор извлечет индекс таблицы каталогов из двух старших бит (в нашем случае это "1", т.е. второй элемент), и выделит адрес каталога из соответствующего элемента. Затем преобразование осуществляется как обычно: следующие 9 бит определяют индекс PDE в каталоге (в нашем случае "4"), полученный PDE содержит базу таблицы страниц, следующие 9 бит -- индекс PTE (в нашем случае "1"). Из этого элемента PTE будет извлечен физически адрес страницы. Допустим, это будет 1 0000 0000. Теперь процессор складывает полученное значение с двенадцатью младшими битами линейного адреса. В результате мы получим физический адрес 1 0000 000C, который и будет подан на шину адреса. Чтобы сделать процесс преобразования более наглядным, приведем алгоритм преобразования линейного адреса в физический на псевдо-С:

qword get_phys_addr(dword addr)
{
dword PDT_addr, /* Физический адрес таблицы каталогов */
PDT_element_index, /* Индекс элемента таблицы каталогов */
PDT_element_addr, /* Физический адрес элемента таблицы каталогов */
PDE_index, /* Индекс элемента каталога таблиц */
PTE_index; /* Индекс элемента таблицы страниц */
qword PD_addr, /* Физический адрес каталога таблиц */
 PDE_addr, /* Физический адрес элемента каталога таблиц */
 PT_addr, /* Физический адрес таблицы страниц */
 PTE_addr, /* Физический адрес элемента таблицы страниц */
 phys_addr; /* Преобразованный физический адрес */

PDT_addr = CR3
 PDT_addr &= 1111 1111 1111 1111 1111 1111 1110 0000 /* Нас интересуют только старшие 27 бит CR3 */
 PDT_element_index = addr & 1100 0000 0000 0000 0000 0000 0000 0000 /* Выделим из адреса индекс элемента таблицы каталогов */
 PDT_element_addr = PDT_addr + PDT_element_index * 0x40 /* Получим физический адрес элемента таблицы каталогов */
 PD_addr = *PDT_element_addr /* Из элемента таблицы каталогов получим адрес каталога */
 PD_addr &= 1111 1111 1111 1111 1111 1111 0000 0000 0000 /* Нас интересуют лишь старшие 24 бита физ. адреса каталога */

PDE_index = addr & 11 1111 1110 0000 0000 0000 0000 0000 /* Выделим из адреса индекс элемента каталога */
PDE_addr = PD_addr + PDE_index * 0x8; /* Получим физический адрес элемента каталога */
 PT_addr = *PDE_addr /* Из элемента каталога получим адрес таблицы страниц */
 PT_addr &= 1111 1111 1111 1111 1111 1111 0000 0000 0000 /* Нас интересуют лишь старшие 24 бита физ. адреса таблицы страниц */

PTE_index = addr & 1 1111 1111 0000 0000 0000 /* Выделим из адреса индекс элемента таблицы страниц */
 PTE_addr = PT_addr + PTE_index * 0x8; /* Получим физический адрес элемента таблицы страниц */
 phys_addr = *PTE_addr /* Из элемента каталога таблиц получим физический адрес страницы */
 phys_addr &= 1111 1111 1111 1111 1111 1111 0000 0000 0000 /* Нас интересуют лишь старшие 24 бита физ. адреса */

phys_addr += addr & 1111 1111 1111 /* Добавим к физ. адресу страницы смещение в странице, и физический адрес готов! */

return phys_addr
} 2 мегабайта
Однако, на этом чудеса PAE не заканчиваются. PAE предлагает еще одну опцию преобразования адреса: с увеличенным размером страниц. Что будет, если избавиться от таблицы страниц, оставив только таблицу каталогов и сами каталоги, а значение физического адреса брать прямо из элемента каталога? В этом случае у нас останется "свободными" 21 нижний бит линейного адреса, что приведет к созданию страниц размером 2 мегабайта. При этом, старшие 11 бит линейного адреса в процессе преобразования будут заменены на 15 старших бит физического, взятых из соответствующего элемента каталога (рисунок 7). Младшие 21 бит линейного адреса при этом являются смещением в странице.


Рисунок 7. Интерпретация бит линейного адреса с размером страниц 2 мегабайта.

Формат элемента каталога в этом случае будет следующим:


Рисунок 8. Элемент каталога таблиц при размере страниц 2 мегабайта.

Выбор размера страницы осуществляется флагом PS элемента каталога. Значение "0" означает, что каталог ссылается на таблицу страниц, размер страницы при этом остается 4 килобайта, "1" означает, что размер страницы, подчиненной элементу каталога, равен двум мегабайтам, и физический адрес следует брать прямо из элемента каталога. Таким образом возможно смешивать четырех -килобайтные и двух-мегабайтные страницы в одном каталоге. Размещение данных в страницах разного размера имеет два преимущества:

1. Большие объемы данных лучше держать в страницах размером 2 мегабайта, т.к. это потенциально позволит уменьшить количество исключений неприсутствия страницы при работе с данными.
2. Преобразованные линейные адреса четырех-килобайтных и двух-мегабайтных страниц хранятся в разных TLB кэшах, что позволяет каждому TLB кэшу содержать больше преобразованных адресов одновременно.

Итак, подведем итоги по PAE
PAE позволяет адресовать до шестидесяти четырех гигабайт физического адресного пространства отображая 32битные адреса на 36битное физическое адресное пространство. Это происходит путем замены старших двадцати бит линейного адреса на двадцать четыре бита физического адреса, позволяя странице, таблице страниц, каталогу таблиц, таблице каталогов, либо всему 32битному пространству отображаться в любую область 36битного адресного пространства. При этом возможен выбор размера страниц между четырьмя килобайтами и двумя мегабайтами.

Продолжение следует.

P.s. Спасибо zloi bandit за полезные замечания!
Previous post Next post
Up