Ответ 1
В самых простых условиях; требование заключается в том, что все, что мог вспомнить CPU TLB, которое было изменено, должно быть аннулировано до того, как произойдет что-либо, что зависит от изменения.
То, что вспомнил процессор, включает в себя:
- окончательные разрешения для страницы (комбинация прав на чтение/запись/выполнение из записи таблицы страниц, записи в каталоге страницы и т.д.); включая, присутствует ли страница или нет (см. предупреждение ниже)
- физический адрес страницы
- флаги "доступ" и "грязные"
- флаги, которые влияют на кеширование
- будь то обычная страница или большая (2 или 4 страницы MiB) или огромная страница (1 гигабайт)
ПРЕДУПРЕЖДЕНИЕ. Поскольку процессоры Intel не помнят "не присутствующие" страницы, документация от Intel может сказать, что вам не нужно делать недействительными при смене страницы с "нет" на "настоящее". Документация Intel подходит только для процессоров Intel. Это неверно для всех процессоров 80x86. Некоторые процессоры (в основном Cyrix) помнят, когда страница была "нет" , и из-за этих процессоров вам приходится делать недействительными при смене страницы с "нет" на "настоящее".
Обратите внимание, что из-за спекулятивного исполнения вы не можете вырезать углы. Например, если вы знаете, что страница никогда не была доступна, вы не можете считать ее не в TLB, потому что TLB, возможно, был спекулятивно выбран.
Я выбрал слова "прежде чем все, что полагается на изменение, произойдет" очень осторожно. Современные процессоры (особенно для длительного режима) кэшируют структуры подкачки более высокого уровня (например, записи PDPT), а не только конечные страницы. Это означает, что если вы измените структуру подкачки более высокого уровня, но сами записи таблицы страниц остаются неизменными, вам все равно необходимо аннулировать.
Это также означает, что можно пропустить недействительность, если ничего не зависит от изменения. Простой пример этого - с доступными и грязными флагами - если вы не полагаетесь на эти флаги (чтобы определить "наименее недавно использовавшиеся" и какие страницы отправлять в swap-пространство), это не имеет большого значения, если процессор Я понимаю, что вы изменили их. Также возможно (не рекомендуется для однопроцессорных, но очень рекомендуется для нескольких процессоров) пропустить отказ TLB в случаях, когда вы получите ошибку страницы, если процессор использует старую/устаревшую информацию TLB, где ошибка страницы обработчик недействителен тогда и только тогда, когда он действительно необходим.
Кроме того; "все, что вспомнил CPU TLB", немного сложно. Часто ОС отображает сами структуры поискового вызова в виртуальное адресное пространство, чтобы обеспечить быстрый/легкий доступ к ним (например, общий трюк "рекурсивного сопоставления", в котором вы притворяетесь, что каталог страниц является таблицей страниц). В этом случае, когда вы изменяете запись в каталоге страницы, вам необходимо аннулировать действующие обычные страницы (как и следовало ожидать), но вам также необходимо аннулировать что-либо, что было изменено в любых сопоставлениях.
Для использования (INVLPG или перезагрузки CR3) существует несколько проблем. Для одной страницы INVLPG будет быстрее. Если вы измените каталог страниц (с учетом 1024 страниц или 512 страниц, в зависимости от того, какой вкус пейджинга), то использование INVLPG в цикле может быть или не быть более дорогостоящим, просто перезагружая CR3 (это зависит от процессора/оборудования и шаблонов доступа для кода, следующего за аннулированием).
В этом есть еще две проблемы. Первое - это переключение задач. При переключении между задачами, использующими разные виртуальные адресные пространства, вы должны изменить CR3. Это означает, что если вы измените что-то, что влияет на большую область (например, каталог страницы), вы можете повысить общую производительность, выполнив настройку задачи раньше, а не перезагружая CR3 сейчас (для недействительности), а затем перезагружая CR3 вскоре (для переключения задачи). В принципе, это оптимизация "убить 2 птицы одним выстрелом".
Другое дело - "глобальные страницы". Обычно там одинаковые страницы во всех виртуальных адресных пространствах (например, ядро). Когда вы перезагружаете CR3 (например, во время переключения задачи), вы не хотите, чтобы TLB для страниц, которые остаются неизменными, недействительны без каких-либо причин, потому что это повредило бы производительность больше, чем необходимо. Чтобы исправить это и улучшить производительность (для Pentium и более поздних версий) есть функция, называемая "глобальными страницами", где вы можете пометить эти общие страницы как глобальные, и они не будут аннулированы при перезагрузке CR3. В этом случае, если вам нужно аннулировать глобальные страницы, вам нужно использовать INVPLG или изменить CR4 (например, отключить, а затем снова включить функцию глобальных страниц). Для больших областей (например, для изменения каталога страниц, а не только для одной страницы) он будет таким же, как и раньше (взаимодействие с CR4 может быть быстрее или медленнее, чем INVLPG в цикле).