В Windows (x86), как индексируется база данных PFN?
В Windows Internals есть раздел о виртуальной памяти. Я понимаю, что поля PFN в записях L4, PDPE и PDE относятся к базовому адресу таблиц следующего уровня, и что PFN PTE относится к расположению страницы в памяти (после сдвига).
Я также понимаю, что база данных Windows PFN содержит дополнительную информацию о каждой странице. Похоже, что он проиндексирован PFN PTE. Это означало бы, что каждый должен существовать на PDE. Это правда? Как это расположено?
Возможно, это в книге, но тогда я должен пропустить это.
1 ответ
База данных PFN находится по высококаноническому виртуальному адресу.0xFFFFFA8000000000
. Это может быть максимальный виртуальный размер0x57FFFFFFFFF
(6ТиБ) (0x1D5555556
записи размера0x30
байт каждый). Это охватывает 512 ТиБ (49 бит), хотя на 64-битных чипсетах Intel обычно разрешено только 256 ТиБ физического пространства (ограничено <=48-битными полями адреса PTE - помните, что виртуальные адреса всегда имеют размер 48 бит в окнах PML4 x64) (0x1D5555556*PageSize = 512TiB
). На моей машине база данных PFN, похоже, взята из0xFFFFFA8000000000 – FFFFFA80197EC000
, последний адресnt!MmNonPagedPoolStart-1
. PFN 0 соответствует первому физическому кадру в PA.0x0000
; PFN 1 соответствует второму физическому кадру в0x1000
и так далее.
Чтобы найти размер базы данных PFN, используйте выражение
? poi(nt!MmNonPagedPoolStart) - poi(nt!MmPfnDatabase)
можно использовать в отладчике. А чтобы найти общее количество записей в базе данных PFN, можно использовать выражение?(poi(nt!MmNonPagedPoolStart) - poi(nt!MmPfnDatabase))/ @@(sizeof(nt!_MMPFN))
[1]
Используйте номер PFN (старшие 36 бит 48-битного физического адреса) для индексации в PFN (умножьте его на размер записи 0x30), чтобы получитьnt!_MMPFN
который описывает этот физический кадр.
Формат ММФН:
Определенные MMPFN будут находиться в определенных списках (нулевой, свободный, резервный, измененный), соединенных прямыми и обратными каналами связи, соединяющими их с другим MMPFN, подключенным к списку.
Тип: тип страницы, представленной этим PFN. (Типы включают активный/действительный, резервный, измененный, измененный без записи, свободный, обнуленный, плохой и переходный.)
Цвет: Помимо связи в списке, записи базы данных PFN используют дополнительное поле для связи физического кадра по «цвету», который представляет собой номер узла NUMA страницы.
ПФН ПТЭ он же. «содержащая страница»: номер физического кадра страницы, содержащей PTE, указывающий на этот физический кадр: !pfn, содержащая страницу
Адрес PTE — это виртуальный адрес структуры PTE, указывающий на страницу (VA памяти ядра, сопоставленный всем процессам). См . здесь , как получить виртуальный адрес PTE, PDE, PDPTE и PML4E для виртуального адреса. Чтобы получить виртуальный адрес, который охватывает этот PTE, вам нужно обратить уравнение в ссылке выше, поэтому#define MiPteToAddress(x) ((PVOID)((ULONG)(x) << 10))
. Два младших бита этого элемента используются в качестве механизма блокировки для сериализации доступа к записи PFN.
Исходное содержимое PTE –MiModifiedPageWriter
записывает измененные страницы из измененного списка в файл подкачки (которые былиinvlpg
d [1] , признаны недействительными и превращены в переходные PTE, а их записи PFN были добавлены в измененный список (если они изменены, в противном случае в резервный список) менеджером рабочего набора) и заменяет их PTE программными PTE, которые содержат адрес страницы в файле подкачки и добавляет PFN в конец резервного списка. Ему также необходимо изменить PTE и преобразовать его в программный PTE файла подкачки, который содержит адрес файла подкачки, в который была записана страница. Я думаю, что он делает это, используя PFN PTE для вычисления физического адреса PTE, который он отображает в гиперпространство, чтобы изменить его, если это не виртуальный адрес ядра (он также должен читать и устанавливать PDE/PDPTE/PML4E Биты доступа/грязные для процесса, если они еще не установлены, поскольку TLB будет использовать контекст системы, а не контекст процесса, когда записывает биты A/D).MiMappedPageWriter
это то, что вместо этого записывает измененные страницы, отображенные в файл, обратно в их файлы или даже страницы, записанные в формате CoW, отображенные в файл, в файл подкачки. Насколько я вижу, этот исходный/восстановленный PTE содержит PTE программного обеспечения файла подкачки в некоторых сценариях и PPTE в других сценариях. Это может предоставить этой конкретной странице данных постоянный адрес файла подкачки, так что при повторной записи она будет записана по тому же адресу и может использоваться для обратной записи страниц в одном непрерывном запросе ввода-вывода. Поле PFN может также позволять копировать этот адрес файла подкачки в PTE только тогда, когда страница перемещается из резервного списка в обнуленный список, так что, пока она находится в резервном списке, PTE все еще может быть ошибкой резервного режима, и страница может быть удовлетворяется из ОЗУ, хотя это показывает, что PTE становится недопустимым типом файла подкачки, в то время как PFN все еще изменяется в процессе записи.
Счетчик ссылок увеличивается, когда страница впервые добавляется в рабочий набор и/или когда страница блокируется в памяти для ввода-вывода (например, драйвером устройства). Счетчик ссылок уменьшается, когда счетчик общих ресурсов становится равным 0 или когда страницы разблокируются из памяти. Когда количество общих ресурсов становится равным 0, страница больше не принадлежит рабочему набору. Затем, если счетчик ссылок также равен нулю, запись базы данных PFN, описывающая страницу, обновляется, чтобы добавить страницу в свободный, резервный или измененный список.
Поле количества общих ресурсов представляет количество PTE, которые ссылаются на эту страницу (поскольку страницы, отмеченные как «только для чтения», «копирование при записи» или «совместное чтение/запись», могут использоваться несколькими процессами).
Если кадр является частью рабочего набора процесса, то он будет иметь индекс рабочего набора, который является индексом в массиве MMWSLE процесса. На массив указывает структура MMWSL, на которую указывает структура MMSUPPORT, на которую указывает структура EPROCESS.
Атрибуты кэширования указывают, является ли страница кэшируемой или нет, или объединяется ли запись и т. д. Флаги указывают такие вещи, как, например, предназначена ли страница для стека ядра, находится ли страница в процессе выгрузки или выгрузки, произошла ли ошибка. в этом процессе «ошибка на странице» и т. д. Тип также известен как. pagelocation указывает тип физического кадра (активный, резервный, измененный и т. д.).
[1] Ему пришлось бы сделать недействительными другие ядра с IPI, прерывая их вектором прерывания, который сбрасывает и делает недействительными их TLB (известный как TLB Shootdown), напримерINVALIDATE_TLB_VECTOR
в Linux, который, по-видимому, реализован с использованием mov to cr3 и ядра, которое отправляет IPI всем, кроме себя, ожидания вращения по битовой маске (smp_invalidate_needed
в Linux) завершенных очисток TLB (что необходимо, поскольку прерываемый ЦП может выполнять большую процедуру MSROM, которая может записывать на эту страницу, а прерывания могут обрабатываться только в конце прекращения использования макроинструкции), чтобы все ядра, которые могут выполняться в контексте этого процесса, не записывайте и не читайте новую страницу, пока она записывается, и вместо этого быстро вызовите ошибку страницы при следующем обходе страницы. То же самое происходит с модифицированным модулем записи страниц, но эти ошибки страниц на других ядрах не смогут быть обработаны, поскольку модуль записи страниц получил блокировку записи PFN, чтобы он мог записать бит выполнения записи на странице в PFN. запись перед отправкой IPI, и эти потоки будут ожидать события мьютекса, указанного в PFN. Ему необходимо получить блокировку и установить бит выполнения перед изменением PTE и выполнением сброса TLB, чтобы это был атомарный процесс, т. е. чтобы ошибка страницы для той же страницы не видела файл подкачки PTE и свободный PFN. запись и инициировать чтение с диска страницы, которая еще не была записана.
Это мое предположение, основанное на руководствах и общих аксиомах. Я еще не проверил, просматривая исходный код диспетчера памяти ReactOS.