Версия этого ответа с хорошим оглавлением и другим контентом .
Я исправлю любую обнаруженную ошибку. Если вы хотите внести большие изменения или добавить недостающий аспект, внесите их самостоятельно, чтобы получить заслуженную репутацию. Незначительные правки могут быть объединены непосредственно в.
Образец кода
Минимальный пример: https://github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S
Как и все остальное в программировании, единственный способ по-настоящему понять это - играть с минимальными примерами.
Что делает эту тему «сложной», так это то, что минимальный пример велик, потому что вам нужно создать свою собственную небольшую ОС.
Руководство Intel
Хотя без примеров понять невозможно, постарайтесь как можно скорее ознакомиться с инструкциями.
Intel описывает разбиение по страницам в Руководстве Intel по системному программированию, том 3 - 325384-056RU, сентябрь 2015 г., глава 4 «Пейджинг».
Особенно интересен рис. 4-4 «Форматы CR3 и записей структуры подкачки при 32-битном подкачке», на котором представлены ключевые структуры данных.
MMU
Пейджинг выполняется блоком управления памятью (MMU) ЦП. Как и многие другие (например, сопроцессор x87 , APIC ), раньше это был отдельный чип, который позже был интегрирован в ЦП. Но этот термин все еще используется.
Главные факты
Логические адреса - это адреса памяти, используемые в «обычном» пользовательском коде (например, содержимое rsi
in mov eax, [rsi]
).
Сначала сегментация преобразует их в линейные адреса, а затем пейджинг преобразует линейные адреса в физические адреса.
(logical) ------------------> (linear) ------------> (physical)
segmentation paging
В большинстве случаев мы можем думать о физических адресах как об индексировании фактических ячеек аппаратной памяти RAM, но это не на 100% верно из-за:
Пейджинг доступен только в защищенном режиме. Использование подкачки в защищенном режиме необязательно. Пейджинг включен, если установлен PG
бит cr0
регистра.
Пейджинг против сегментации
Одно из основных различий между разбиением на страницы и сегментацией заключается в следующем:
- пейджинг разбивает оперативную память на блоки равного размера, называемые страницами
- сегментация разбивает память на куски произвольного размера
Это главное преимущество разбиения на страницы, поскольку блоки равного размера делают вещи более управляемыми.
Пейджинг стал настолько популярным, что поддержка сегментации была прекращена в x86-64 в 64-битном режиме, основном режиме работы для нового программного обеспечения, где он существует только в режиме совместимости, который имитирует IA32.
заявка
Пейджинг используется для реализации процессов виртуальных адресных пространств в современных ОС. С виртуальными адресами ОС может разместить два или более параллельных процесса в одной оперативной памяти таким образом, чтобы:
- обе программы не должны ничего знать друг о друге
- память обеих программ может увеличиваться и уменьшаться по мере необходимости
- переключение между программами очень быстрое
- одна программа никогда не может получить доступ к памяти другого процесса
Пейджинг исторически появлялся после сегментации и в значительной степени заменял его для реализации виртуальной памяти в современных ОС, таких как Linux, поскольку легче управлять фрагментами памяти страниц фиксированного размера, а не сегментами переменной длины.
Аппаратная реализация
Подобно сегментации в защищенном режиме (когда изменение регистра сегмента вызывает загрузку из GDT или LDT), оборудование подкачки использует структуры данных в памяти для выполнения своей работы (таблицы страниц, каталоги страниц и т. Д.).
Формат этих структур данных фиксируется оборудованием , но именно ОС должна правильно настроить эти структуры данных в ОЗУ и управлять ими, а также сообщить оборудованию, где их найти (через cr3
).
Некоторые другие архитектуры оставляют подкачку страниц почти полностью в руках программного обеспечения, поэтому промах TLB запускает функцию, предоставляемую ОС, для просмотра таблиц страниц и вставки нового сопоставления в TLB. Это оставляет возможность выбора форматов таблиц страниц операционной системой, но делает маловероятным, что оборудование сможет перекрывать обход страниц с выполнением других инструкций вне очереди, как это может сделать x86 .
Пример: упрощенная одноуровневая схема подкачки
Это пример того, как подкачка работает в упрощенной версии архитектуры x86 для реализации пространства виртуальной памяти.
Таблицы страниц
ОС может предоставить им следующие таблицы страниц:
Таблица страниц, предоставленная ОС процессу 1:
RAM location physical address present
----------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0x00000 1
PT1 + 2 * L 0x00003 1
PT1 + 3 * L 0
... ...
PT1 + 0xFFFFF * L 0x00005 1
Таблица страниц, переданная ОС процессу 2:
RAM location physical address present
----------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000B 1
PT2 + 2 * L 0
PT2 + 3 * L 0x00003 1
... ... ...
PT2 + 0xFFFFF * L 0x00004 1
Куда:
PT1
и PT2
: исходное положение таблиц 1 и 2 в ОЗУ.
Примеры значений: 0x00000000
, 0x12345678
и т.д.
Эти значения определяет ОС.
L
: длина записи таблицы страниц.
present
: указывает, что страница присутствует в памяти.
Таблицы страниц расположены в ОЗУ. Например, они могут быть расположены как:
--------------> 0xFFFFFFFF
--------------> PT1 + 0xFFFFF * L
Page Table 1
--------------> PT1
--------------> PT2 + 0xFFFFF * L
Page Table 2
--------------> PT2
--------------> 0x0
Начальные местоположения в ОЗУ для обеих таблиц страниц произвольны и контролируются ОС. Операционная система должна гарантировать, что они не перекрываются!
Каждый процесс не может напрямую касаться каких-либо таблиц страниц, хотя он может делать запросы к ОС, которые вызывают изменение таблиц страниц, например, запрашивая сегменты стека или кучи большего размера.
Страница представляет собой фрагмент размером 4 КБ (12 бит), а поскольку адреса имеют 32 бита, для идентификации каждой страницы требуется только 20 бит (20 + 12 = 32, то есть 5 символов в шестнадцатеричной системе счисления). Это значение фиксируется аппаратно.
Записи в таблице страниц
Таблица страниц - это ... таблица записей таблицы страниц!
Точный формат записей в таблице фиксируется оборудованием .
В этом упрощенном примере записи таблицы страниц содержат только два поля:
bits function
----- -----------------------------------------
20 physical address of the start of the page
1 present flag
так что в этом примере разработчики оборудования могли выбрать L = 21
.
Большинство реальных записей таблицы страниц имеют другие поля.
Было бы непрактично выравнивать объекты по 21 биту, поскольку память адресуется байтами, а не битами. Следовательно, даже если в этом случае требуется только 21 бит, разработчики оборудования, вероятно, предпочтут L = 32
ускорить доступ и просто зарезервируют биты, оставшиеся биты для дальнейшего использования. Фактическое значение для L
x86 - 32 бита.
Трансляция адресов по одноуровневой схеме
После того, как таблицы страниц настроены операционной системой, преобразование адресов между линейными и физическими адресами выполняется аппаратными средствами .
Когда ОС хочет активировать процесс 1, она устанавливает cr3
в PT1
начало таблицы для процесса 1.
Если Процесс 1 хочет получить доступ к линейному адресу 0x00000001
, аппаратная схема подкачки автоматически выполняет следующие действия для ОС:
разделите линейный адрес на две части:
| page (20 bits) | offset (12 bits) |
Итак, в этом случае у нас будет:
- page = 0x00000
- смещение = 0x001
загляните в таблицу страниц 1, потому что cr3
указывает на нее.
посмотрите запись, 0x00000
потому что это часть страницы.
Аппаратное обеспечение знает, что эта запись находится по адресу RAM PT1 + 0 * L = PT1
.
поскольку он присутствует, доступ действителен
рядом с таблицей страниц номер страницы 0x00000
находится по адресу 0x00001 * 4K = 0x00001000
.
чтобы найти окончательный физический адрес, нам просто нужно добавить смещение:
00001 000
+ 00000 001
-----------
00001 001
потому что 00001
это физический адрес страницы, найденной в таблице, и 001
смещение.
Как видно из названия, смещение всегда просто добавляется к физическому адресу страницы.
затем оборудование получает память в этом физическом месте.
Таким же образом для процесса 1 произойдут следующие переводы:
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00002 000 00002 000
FFFFF 000 00005 000
Например, при доступе к адресу 00001000
часть страницы - 00001
это аппаратное обеспечение, которое знает, что его запись в таблице страниц расположена по адресу RAM: PT1 + 1 * L
( 1
из-за части страницы), и именно там оно будет ее искать.
Когда ОС хочет переключиться на процесс 2, все, что ей нужно сделать, это cr3
указать ссылку на страницу 2. Это так просто!
Теперь для процесса 2 произойдут следующие переводы:
linear physical
--------- ---------
00000 002 00001 002
00000 003 00001 003
00000 FFF 00001 FFF
00001 000 00000 000
00001 001 00000 001
00001 FFF 00000 FFF
00003 000 00003 000
FFFFF 000 00004 000
Один и тот же линейный адрес преобразуется в разные физические адреса для разных процессов , в зависимости только от значения внутри cr3
.
Таким образом, каждая программа может ожидать начала 0
и окончания своих данных FFFFFFFF
, не беспокоясь о точных физических адресах.
Ошибка страницы
Что, если процесс 1 пытается получить доступ к адресу внутри страницы, которой нет?
Оборудование уведомляет программное обеспечение с помощью исключения ошибки страницы.
Затем обычно операционная система должна зарегистрировать обработчик исключений, чтобы решить, что делать.
Возможно, что доступ к странице, которой нет в таблице, является ошибкой программирования:
int is[1];
is[2] = 1;
но могут быть случаи, когда это приемлемо, например в Linux, когда:
программа хочет увеличить свой стек.
Он просто пытается получить доступ к определенному байту в заданном возможном диапазоне, и, если ОС удовлетворена, он добавляет эту страницу в адресное пространство процесса.
страница была перенесена на диск.
ОС потребуется выполнить некоторую работу за процессами, чтобы вернуть страницу в ОЗУ.
ОС может обнаружить, что это так, на основе содержимого остальной части записи таблицы страниц, поскольку, если флаг наличия снят, другие записи записи таблицы страниц полностью оставляются для ОС, чтобы она могла.
Например, в Linux, если присутствует = 0:
если все поля записи таблицы страниц равны 0, неверный адрес.
в противном случае страница была заменена на диск, и фактические значения этих полей кодируют положение страницы на диске.
В любом случае ОС должна знать, какой адрес вызвал ошибку страницы, чтобы иметь возможность справиться с проблемой. Вот почему хорошие разработчики IA32 устанавливают значение cr2
этого адреса всякий раз, когда происходит сбой страницы. Затем обработчик исключений может просто посмотреть, cr2
чтобы получить адрес.
Упрощения
Упрощения реальности, которые упрощают понимание этого примера:
все реальные схемы подкачки используют многоуровневую подкачку для экономии места, но здесь показана простая одноуровневая схема.
таблицы страниц содержали только два поля: 20-битный адрес и 1-битный флаг присутствия.
Таблицы реальных страниц содержат в общей сложности 12 полей и, следовательно, другие функции, которые были опущены.
Пример: многоуровневая схема подкачки
Проблема с одноуровневой схемой подкачки состоит в том, что она занимает слишком много оперативной памяти: 4G / 4K = 1M записей на процесс. Если каждая запись имеет длину 4 байта, это составит 4 МБ на процесс , что слишком много даже для настольного компьютера: ps -A | wc -l
говорит, что сейчас у меня запущено 244 процесса, так что это займет около 1 ГБ моей оперативной памяти!
По этой причине разработчики x86 решили использовать многоуровневую схему, уменьшающую использование оперативной памяти.
Обратной стороной этой системы является немного большее время доступа.
В простой трехуровневой схеме подкачки, используемой для 32-битных процессоров без PAE, 32 бита адреса делятся следующим образом:
| directory (10 bits) | table (10 bits) | offset (12 bits) |
Каждый процесс должен иметь один и только один связанный с ним каталог страниц, поэтому он будет содержать по крайней мере 2^10 = 1K
записи каталога страниц, что намного лучше, чем минимальный 1M, требуемый для одноуровневой схемы.
Таблицы страниц выделяются только по мере необходимости ОС. Каждая таблица 2^10 = 1K
страниц имеет записи каталога страниц
Каталоги страниц содержат ... записи каталога страниц! Записи каталога страниц такие же, как записи таблицы страниц, за исключением того, что они указывают на адреса RAM таблиц страниц, а не на физические адреса таблиц . Поскольку эти адреса имеют ширину всего 20 бит, таблицы страниц должны находиться в начале страниц размером 4 КБ.
cr3
теперь указывает на расположение в ОЗУ каталога страниц текущего процесса вместо таблиц страниц.
Записи в таблицах страниц вообще не меняются от одноуровневой схемы.
Таблицы страниц отличаются от одноуровневой схемы, потому что:
- каждый процесс может иметь до 1 КБ таблиц страниц, по одной на запись каталога страниц.
- каждая таблица страниц содержит ровно 1K записей вместо 1M записей.
Причина использования 10 бит на первых двух уровнях (а не, скажем, 12 | 8 | 12
) заключается в том, что каждая запись в таблице страниц имеет длину 4 байта. Тогда 2 ^ 10 записей каталогов страниц и таблиц страниц будут хорошо вписываться в страницы размером 4 КБ. Это означает, что для этой цели быстрее и проще выделять и освобождать страницы.
Трансляция адресов в многоуровневой схеме
Каталог страниц, предоставленный ОС процессу 1:
RAM location physical address present
--------------- ----------------- --------
PD1 + 0 * L 0x10000 1
PD1 + 1 * L 0
PD1 + 2 * L 0x80000 1
PD1 + 3 * L 0
... ...
PD1 + 0x3FF * L 0
Таблицы страниц, передаваемые ОС процессу 1 в PT1 = 0x10000000
( 0x10000
* 4K):
RAM location physical address present
--------------- ----------------- --------
PT1 + 0 * L 0x00001 1
PT1 + 1 * L 0
PT1 + 2 * L 0x0000D 1
... ...
PT1 + 0x3FF * L 0x00005 1
Таблицы страниц, передаваемые ОС процессу 1 в PT2 = 0x80000000
( 0x80000
* 4K):
RAM location physical address present
--------------- ----------------- --------
PT2 + 0 * L 0x0000A 1
PT2 + 1 * L 0x0000C 1
PT2 + 2 * L 0
... ...
PT2 + 0x3FF * L 0x00003 1
где:
PD1
: начальная позиция каталога страниц процесса 1 в ОЗУ.
PT1
и PT2
: начальная позиция таблицы страниц 1 и таблицы страниц 2 для процесса 1 в ОЗУ.
Итак, в этом примере каталог страниц и таблица страниц могут храниться в ОЗУ примерно так:
----------------> 0xFFFFFFFF
----------------> PT2 + 0x3FF * L
Page Table 1
----------------> PT2
----------------> PD1 + 0x3FF * L
Page Directory 1
----------------> PD1
----------------> PT1 + 0x3FF * L
Page Table 2
----------------> PT1
----------------> 0x0
0x00801004
Пошагово переведем линейный адрес .
Мы предполагаем cr3 = PD1
, что он указывает на только что описанный каталог страниц.
В двоичном формате линейный адрес:
0 0 8 0 1 0 0 4
0000 0000 1000 0000 0001 0000 0000 0100
Группировка по принципу 10 | 10 | 12
дает:
0000000010 0000000001 000000000100
0x2 0x1 0x4
который дает:
- запись в каталоге страниц = 0x2
- запись в таблице страниц = 0x1
- смещение = 0x4
Таким образом, оборудование ищет запись 2 в каталоге страниц.
В таблице каталога страниц указано, что таблица страниц находится по адресу 0x80000 * 4K = 0x80000000
. Это первый доступ к ОЗУ процесса.
Поскольку запись таблицы страниц есть 0x1
, оборудование просматривает запись 1 таблицы страниц 0x80000000
, которая сообщает ему, что физическая страница расположена по адресу 0x0000C * 4K = 0x0000C000
. Это второй доступ к ОЗУ процесса.
Наконец, оборудование подкачки добавляет смещение, и конечный адрес равен 0x0000C004
.
Другие примеры переведенных адресов:
linear 10 10 12 split physical
-------- --------------- ----------
00000001 000 000 001 00001001
00001001 000 001 001 page fault
003FF001 000 3FF 001 00005001
00400000 001 000 000 page fault
00800001 002 000 001 0000A001
00801008 002 001 008 0000C008
00802008 002 002 008 page fault
00B00001 003 000 000 page fault
Ошибки страниц возникают, если отсутствует запись каталога страниц или запись таблицы страниц.
Если ОС хочет запустить другой процесс одновременно, она предоставит второму процессу отдельный каталог страниц и свяжет этот каталог с отдельными таблицами страниц.
64-битные архитектуры
64 бита по-прежнему слишком большой адрес для текущих размеров ОЗУ, поэтому большинство архитектур будет использовать меньше бит.
x86_64 использует 48 бит (256 ТиБ), а PAE устаревшего режима уже допускает 52-битные адреса (4 ПиБ).
12 из этих 48 бит уже зарезервированы для смещения, что оставляет 36 бит.
Если используется двухуровневый подход, лучшим разделением будет два 18-битных уровня.
Но это будет означать, что в каталоге страниц будут 2^18 = 256K
записи, которые потребуют слишком много ОЗУ: близко к одноуровневой подкачке страниц для 32-битных архитектур!
Следовательно, 64-битные архитектуры создают еще более высокие уровни страниц, обычно 3 или 4.
x86_64 использует 4 уровня в 9 | 9 | 9 | 12
схеме, так что верхний уровень занимает только 2^9
записи более высокого уровня.
PAE
Расширение физического адреса.
С 32-битным адресом можно адресовать только 4 ГБ ОЗУ.
Это стало ограничением для больших серверов, поэтому Intel представила механизм PAE для Pentium Pro.
Чтобы решить эту проблему, Intel добавила 4 новые адресные строки, чтобы можно было адресовать 64 ГБ.
Структура таблицы страниц также изменяется, если PAE включен. Точный способ его изменения зависит от того, включен или выключен PSE.
PAE включается и выключается PAE
битом cr4
.
Даже если общая адресуемая память составляет 64 ГБ, отдельный процесс по-прежнему может использовать только до 4 ГБ. Однако ОС может размещать разные процессы в разных блоках по 4 ГБ.
PSE
Расширение размера страницы.
Позволяет страницам быть 4M (или 2M, если PAE включен) в длину вместо 4K.
PSE включается и выключается PAE
битом cr4
.
Схемы таблиц страниц PAE и PSE
Если активны PAE и PSE, используются разные схемы уровней пейджинга:
без PAE и без PSE: 10 | 10 | 12
нет PAE и PSE : 10 | 22
.
22 - это смещение в пределах страницы 4 Мб, поскольку 22 бита адресуют 4 Мб.
PAE и без PSE: 2 | 9 | 9 | 12
Причина, по которой 9 используется дважды вместо 10, заключается в том, что теперь записи больше не могут умещаться в 32 бита, которые все были заполнены 20 битами адреса и 12 значащими или зарезервированными битами флага.
Причина в том, что 20 битов уже недостаточно для представления адресов таблиц страниц: теперь необходимо 24 бита из-за 4 дополнительных проводов, добавленных к процессору.
Поэтому разработчики решили увеличить размер записи до 64 бит, а для того, чтобы уместить их в одну таблицу страниц, необходимо уменьшить количество записей до 2 ^ 9 вместо 2 ^ 10.
Начальные 2 - это новый уровень страницы, называемый таблицей указателей каталога страниц (PDPT), поскольку он указывает на каталоги страниц и заполняет 32-битный линейный адрес. PDPT также имеют ширину 64 бита.
cr3
теперь указывает на PDPT, которые должны быть на первых четырех 4 ГБ памяти и выровнены по 32-битным кратным для эффективности адресации. Это означает, что теперь cr3
имеет 27 значащих битов вместо 20: 2 ^ 5 для 32 кратных * 2 ^ 27, чтобы заполнить 2 ^ 32 первых 4 ГБ.
PAE и PSE: 2 | 9 | 21
Дизайнеры решили оставить поле шириной 9 бит, чтобы оно поместилось на одной странице.
Остается 23 бита. Оставляя 2 для PDPT, чтобы сохранить единообразие с случаем PAE без PSE, оставляет 21 для смещения, что означает, что страницы имеют ширину 2M вместо 4M.
TLB
Буфер предвидения трансляции (TLB) - это кэш для адресов подкачки.
Поскольку это кэш, он разделяет многие проблемы проектирования кеша ЦП, такие как уровень ассоциативности.
В этом разделе описывается упрощенный полностью ассоциативный TLB с 4 отдельными адресными записями. Обратите внимание, что, как и другие кеши, реальные TLB обычно не являются полностью ассоциативными.
Основная операция
После того, как происходит преобразование линейного адреса в физический, он сохраняется в TLB. Например, TLB с 4 записями запускается в следующем состоянии:
valid linear physical
------ ------- ---------
> 0 00000 00000
0 00000 00000
0 00000 00000
0 00000 00000
Значок >
указывает на заменяемую текущую запись.
и после 00003
преобразования линейного адреса страницы в физический адрес 00005
TLB становится:
valid linear physical
------ ------- ---------
1 00003 00005
> 0 00000 00000
0 00000 00000
0 00000 00000
и после второго перевода 00007
to 00009
это становится:
valid linear physical
------ ------- ---------
1 00003 00005
1 00007 00009
> 0 00000 00000
0 00000 00000
Теперь, если 00003
требуется повторная трансляция, оборудование сначала просматривает TLB и определяет его адрес с помощью одного доступа к ОЗУ 00003 --> 00005
.
Конечно, 00000
его нет в TLB, поскольку 00000
в качестве ключа нет действительной записи .
Политика замены
Когда TLB заполняется, старые адреса перезаписываются. Как и в случае с кешем ЦП, политика замены - потенциально сложная операция, но простой и разумный эвристический метод состоит в удалении наименее использованной записи (LRU).
С LRU, начиная с состояния:
valid linear physical
------ ------- ---------
> 1 00003 00005
1 00007 00009
1 00009 00001
1 0000B 00003
добавление 0000D -> 0000A
даст:
valid linear physical
------ ------- ---------
1 0000D 0000A
> 1 00007 00009
1 00009 00001
1 0000B 00003
CAM
Использование TLB ускоряет трансляцию, поскольку для начальной трансляции требуется один доступ на каждый уровень TLB , что означает 2 для простой 32-битной схемы и 3 или 4 для 64-битных архитектур.
TLB обычно реализуется как дорогостоящий тип ОЗУ, называемый памятью с адресацией по содержимому (CAM). CAM реализует ассоциативную карту на оборудовании, то есть структуру, которая по ключу (линейный адрес) извлекает значение.
Отображения также могут быть реализованы на адресах RAM, но отображения CAM могут потребовать гораздо меньше записей, чем отображение RAM.
Например, карта, на которой:
- и ключи, и значения имеют 20 бит (в случае простых схем подкачки)
- не более 4 значений должны быть сохранены каждый раз
может храниться в TLB с 4 записями:
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
FFFFF 00000
Однако, чтобы реализовать это с ОЗУ, необходимо иметь 2 ^ 20 адресов :
linear physical
------- ---------
00000 00001
00001 00010
00010 00011
... (from 00011 to FFFFE)
FFFFF 00000
что будет даже дороже, чем использование TLB.
Недействительные записи
При cr3
изменении все записи TLB становятся недействительными, потому что будет использоваться новая таблица страниц для нового процесса, поэтому маловероятно, что какие-либо из старых записей имеют какое-либо значение.
X86 также предлагает invlpg
инструкцию, которая явно аннулирует одну запись TLB. Другие архитектуры предлагают еще больше инструкций для недействительных записей TLB, таких как аннулирование всех записей в заданном диапазоне.
Некоторые процессоры x86 выходят за рамки требований спецификации x86 и обеспечивают большую согласованность, чем она гарантирует, между изменением записи таблицы страниц и ее использованием, когда она еще не была кэширована в TLB . Очевидно, Windows 9x полагалась на это для правильности, но современные процессоры AMD не обеспечивают последовательного просмотра страниц. Процессоры Intel это делают, хотя для этого им приходится выявлять ложные предположения. Воспользоваться этим, вероятно, является плохой идеей, поскольку, вероятно, здесь не так много пользы, и есть большой риск вызвать тонкие, чувствительные к времени проблемы, которые будет трудно отладить.
Использование ядра Linux
Ядро Linux широко использует возможности подкачки страниц x86, чтобы обеспечить быстрое переключение процессов с небольшой фрагментацией данных.
В v4.2
, посмотрите под arch/x86/
:
include/asm/pgtable*
include/asm/page*
mm/pgtable*
mm/page*
Похоже, что для представления страниц не определены структуры, только макросы: include/asm/page_types.h
особенно интересно. Отрывок:
#define _PAGE_BIT_PRESENT 0 /* is present */
#define _PAGE_BIT_RW 1 /* writeable */
#define _PAGE_BIT_USER 2 /* userspace addressable */
#define _PAGE_BIT_PWT 3 /* page write through */
arch/x86/include/uapi/asm/processor-flags.h
определяет CR0
, и в частности PG
битовую позицию:
#define X86_CR0_PG_BIT 31 /* Paging */
Библиография
Свободно:
rutgers-pxk-416, глава "Управление памятью: конспекты лекций"
Хороший исторический обзор методов организации памяти, используемых в более старых ОС.
Несвободно: