Как работает подкачка x86?


этот вопрос призван заполнить вакуум хорошей свободной информации по этому вопросу.

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

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

рекомендации:

  • ответы должны быть начинающий дружелюбный:
    • бетон, но, возможно, упрощенные примеры очень важны
    • применения показанных принципиальных схем радушны
  • цитирование полезных ресурсов-это хорошо
  • небольшие отступления в том, как OSs используют функции подкачки приветствуются
  • PAE и PSE объяснения приветствуются
  • небольшие отступления в x86_64 приветствуются

вопросы и почему я думаю, что они не дураки:

2 64

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 реализует уровни привилегий (называется "кольца"), и пользовательский код выполняется на уровне привилегий, который слишком низок, чтобы позволить ему изменять таблицы страниц ЦП.