Как работает подкачка x86?
этот вопрос призван заполнить вакуум хорошей свободной информации по этому вопросу.
Я считаю, что хороший ответ будет вписываться в один большой ответ SO или, по крайней мере, в несколько ответов.
основная цель состоит в том, чтобы дать полным новичкам достаточно информации, чтобы они могли самостоятельно взять руководство и понять основные концепции ОС, связанные с подкачкой.
рекомендации:
- ответы должны быть начинающий дружелюбный:
- бетон, но, возможно, упрощенные примеры очень важны
- применения показанных принципиальных схем радушны
- цитирование полезных ресурсов-это хорошо
- небольшие отступления в том, как OSs используют функции подкачки приветствуются
- PAE и PSE объяснения приветствуются
- небольшие отступления в x86_64 приветствуются
вопросы и почему я думаю, что они не дураки:
как работают таблицы страниц x86?: название почти такое же, как этот вопрос, но орган задает конкретные вопросы, связанные с cr3 и TLB. Этот вопрос является подмножеством этого.
как работает виртуализация x86: тело запрашивает только источники.
2 ответа:
версия этого ответа с хорошим TOC и больше контента.
я исправлю любую ошибку, о которой сообщается. Если вы хотите сделать большие изменения или добавить недостающий аспект, сделать их на ваши собственные ответы, чтобы получить заслуженную репутация. Незначительные изменения могут быть объединены непосредственно в.
пример кода
минимальный пример: https://github.com/cirosantilli/x86-bare-metal-examples/blob/5c672f73884a487414b3e21bd9e579c67cd77621/paging.S
как и все остальное в программировании, единственный способ действительно понять это-играть с минимальными примерами.
что делает это "трудным" предметом, так это то, что минимальный пример большой, потому что вам нужно сделать свою собственную небольшую ОС.
руководство Intel
хотя это невозможно понять не имея в виду примеров, постарайтесь как можно скорее ознакомиться с руководствами.
Intel описывает подкачку в руководство по программированию Intel Manual Volume 3 System - 325384-056US сентябрь 2015 Глава 4 "Подкачки".
особенно интересен рисунок 4-4 "форматы записей CR3 и Paging-Structure с 32-битной подкачкой", который дает ключевые структуры данных.
ММУ
подкачка осуществляется с помощью память Блок Управления (MMU) часть процессора. Как и многие другие (например,x87, так сопроцессор, APIC), это раньше было отдельным чипом в первые дни, который позже был интегрирован в процессор. Но этот термин все еще используется.
общие факты
логические адреса-это адреса памяти, используемые в" обычном " пользовательском земельном коде (например, содержимое
rsi
наmov eax, [rsi]
).первая сегментация переводит их в линейные адреса, а затем подкачка затем преобразует линейные адреса в физические адреса.
(logical) ------------------> (linear) ------------> (physical) segmentation paging
большую часть времени мы можем думать о физических адресах как об индексации фактических ячеек аппаратной памяти ОЗУ, но это не 100% верно из-за:
подкачки доступна только в защищенном режиме. Использование подкачки в защищенный режим является необязательным. Подкачки на эквивалентность
PG
битcr0
регистр имеет значение.разбиение на страницы и сегментация
одно из основных различий между подкачкой и сегментацией заключается в следующем:
- подкачка разбивает ОЗУ на равные по размеру куски, называемые страницами
- сегментация разбивает память на куски произвольных размеров
это главное преимущество подкачки, так как равные по размеру куски делают вещи более управляемый.
пейджинг стал настолько популярным, что поддержка сегментации была отброшена в x86-64 в 64-битном режиме, основном режиме работы для нового программного обеспечения, где он существует только в режиме совместимости, который эмулирует IA32.
приложение
подкачка используется для реализации процессов виртуальных адресных пространств на современных ОС. С виртуальными адресами ОС может поместиться два или более параллельных процессов на одной оперативной памяти в пути что:
- обе программы не должны ничего знать о других
- память обеих программ может расти и сокращаться по мере необходимости
- переключение между программами происходит очень быстро
- одна программа не может получить доступ к памяти другого процесса
пейджинг исторически появился после сегментации и в значительной степени заменил ее для реализации виртуальной памяти в современных ОС, таких как Linux, так как это проще управление фиксированным размером кусков памяти страниц вместо сегментов переменной длины.
реализация оборудования
подобно сегментации в защищенном режиме (где изменение регистра сегмента вызывает нагрузку от GDT или LDT), оборудование подкачки использует структуры данных в памяти для выполнения своей работы (таблицы страниц, каталоги страниц и т. д.).
формат этих структур данных фиксированного оборудование, но это до ОС, чтобы настроить и правильно управлять этими структурами данных в ОЗУ, а также сообщать аппаратным средствам, где их найти (через
cr3
).некоторые другие архитектуры оставляют подкачку почти полностью в руках программного обеспечения, поэтому TLB miss запускает функцию, поставляемую ОС, чтобы ходить по таблицам страниц и вставлять новое отображение в 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
начальные местоположения в ОЗУ для обеих таблиц страниц являются произвольными и управляются ОС. Это зависит от ОС, чтобы убедиться, что они не перекрываются!
каждый процесс не может напрямую касаться таблиц страниц, хотя он может делать запросы к ОС, которые вызывают изменение таблиц страниц, например, запрашивая больший стек или кучу сегменты.
страница представляет собой кусок 4KB (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 хочет получить доступ к линейному адресу
0x00000001
, листание оборудование схема автоматически делает следующее для ОС:
разделить линейный адрес на две части:
| page (20 bits) | offset (12 bits) |
так что в этом случае мы бы:
- страница = 0x00000
- offset = 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
аппаратное обеспечение знает, что его запись таблицы страниц находится по адресу ОЗУ: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, недопустимый адрес.
другое, страница была заменена на диск, и фактические значения этих полей кодировать положение страницы на диск.
в любом случае, ОС должна знать, какой адрес вызвал ошибку страницы, чтобы иметь возможность справиться с проблемой. Вот почему разработчики nice IA32 установили значение
cr2
по этому адресу всякий раз, когда возникает ошибка страницы. Обработчик исключений может просто заглянуть вcr2
получить адрес.упрощений
упрощения к реальности, которые делают этот пример проще поймите:
все реальные схемы подкачки используют многоуровневую подкачку для экономии места, но это показало простую одноуровневую схему.
таблицы страниц содержали только два поля: 20-битный адрес и 1-битный флаг.
реальные таблицы страниц содержат в общей сложности 12 полей, и поэтому другие функции, которые были опущены.
пример: многоуровневая подкачки схема
проблема с одноуровневой схемой подкачки заключается в том, что она займет слишком много оперативной памяти: 4G / 4K = 1M записей на
вот очень короткий, высокоуровневый ответ:
процессор x86 работает в одном из нескольких возможных режимов (примерно: реальный, защищенный, 64-разрядный). Каждый режим может использовать одну из нескольких возможных моделей адресации памяти (но не каждый режим может использовать каждую модель), а именно: адресация в реальном режиме, сегментированная адресация и плоская линейная адресация.
в современном мире актуальна только плоско-линейная адресация в защищенном или 64-битном режиме, и эти два режима по существу являются то же самое, с основной разницей в размере машинного слова и, следовательно, адресуемого объема памяти.
теперь режим адресации памяти придает значение операндам памяти машинных инструкций (например,
mov DWORD PTR [eax], 25
, в котором хранится 32-бит (он жеdword
) целое число со значением 25 в памяти, адрес которого хранится вeax
32-битный регистр). В плоско-линейной адресации это число вeax
позволено побежать над одиночным, непрерывным рядом, от нул до максимальное значение (в нашем случае это 232 - 1).однако плоско-линейная адресация может быть либо paged или не вызывали. Без подкачки адрес напрямую ссылается на физическую память. С подкачка, блок управления памятью процессора (или MMU) прозрачно подает нужный адрес (теперь называемый виртуальный адрес) в механизм поиска, так называемый таблицы страницы и получает новое значение, которое интерпретируется как физический адрес. Исходная операция теперь работает с этим новым, переведенным адресом в физической памяти, даже если пользователь видит только виртуальный адрес.
ключевым преимуществом подкачки является то, что таблицы страниц управляются операционной системой. Таким образом, операционная система может изменять и заменять таблицы страниц произвольно, например, при "переключении задач". Он может хранить целую коллекцию таблиц страниц, по одной для каждого "процесса", и всякий раз, когда он решает, что определенный процесс будет выполняться на данном процессоре, он загружает таблицы страниц процесса в MMU этого процессора (каждый процессор имеет свой собственный набор таблиц страниц). В результате каждый процесс видит свой собственный виртуальный адресное пространство, которое выглядит одинаково независимо от того, какие физические страницы были свободны, когда ОС должна была выделить для него память. Он никогда не знает о памяти любого другого процесса, так как он не может напрямую обращаться к физической памяти.
таблицы страниц вложенные древовидные структуры данных, хранящиеся в обычной памяти, записываются ОС, но читаются непосредственно аппаратными средствами, поэтому формат фиксирован. Они "загружаются" в MMU, устанавливая специальный регистр управления процессором, чтобы указать на таблицу верхнего уровня. Процессор использует кэш под названием TLB для запоминания поисков, поэтому повторные обращения к тем же нескольким страницам намного быстрее, чем разбросанные обращения, по причинам TLB-miss, а также по обычным причинам кэша данных. Обычно термин "запись TLB" используется для обозначения записи таблицы страниц, даже если они не кэшируются в TLB.
и в случае, если вы беспокоитесь, что процесс может просто отключить подкачку или попытаться изменить таблицы страниц: это не допускается, так как x86 реализует уровни привилегий (называется "кольца"), и пользовательский код выполняется на уровне привилегий, который слишком низок, чтобы позволить ему изменять таблицы страниц ЦП.